Action Control
Connectors: Stripe, Shopify and Webhook
Connect with Stripe and Shopify in one click (read-only for the audit, execution when you enable it), the restricted-key fallback, and the Webhook connector contract.
A connector is how Audon reads provider context and executes an action. Stripe and Shopify connect in one click with their official app installs; your own systems connect through a signed Webhook. One install covers the audit and live actions. Each connector is read_only (Audon only reads: the free action audit) or execute (protection on: live actions run through it). A new connection starts read-only; a signed-in person turns on protection, a switch in Audon, not a second install. Nothing is written to the provider before that. Tokens and keys are envelope-encrypted and never shown again.
Stripe
Connect with Stripe (recommended) installs the Audon app in your Stripe account through Stripe’s OAuth install link, once. Stripe App permissions are fixed per app, so the one app asks for everything the actions need:
| Permissions | Used for |
|---|---|
charge_read, payment_intent_read, customer_read, coupon_read, subscription_read, event_read | The free action audit, the checks’ provider context, verification and install events |
charge_write (refunds), customer_write (balance credits), coupon_write, subscription_write | Executing checked actions, only after you turn on protection |
Audon only reads until you turn on protection for an agent. The connector starts read-only; Audon never sends a write with a read-only connector, whatever the app’s permissions. Connectors installed with the earlier read-only app (“Audon Action Audit”) keep working read-only; Reconnect to turn on protection installs the Audon app on the same connector.
Audon receives an access token (1 hour) and a rolling refresh token (1 year) for your account; it refreshes the token itself. The connector shows the connected account and whether it is in test mode. Uninstalling the app in Stripe disconnects it in Audon (and the reverse: Disconnect in Audon destroys the tokens; uninstall the app in Stripe as well).
Use an API key instead: a restricted key (rk_live_… or rk_test_…) with the same permissions works too. A secret key (sk_…) is refused. Both ways run the same checks, actions and reconciliation.
| Action | Stripe object | App permission | Restricted key |
|---|---|---|---|
refund.create | Refund on a charge or payment intent | charge_write | Refunds: write |
credit.create | Customer balance transaction | customer_write | Customers: write |
discount.create | Single-use coupon, optionally applied to a subscription | coupon_write (+ subscription_write) | Coupons (and Subscriptions) |
subscription.cancel | Cancel now or at period end | subscription_write | Subscriptions: write |
subscription.update | Price, quantity, cancel at period end | subscription_write | Subscriptions: write |
- Read access to charges, refunds, customers, coupons and subscriptions gives the business rules their context (amount captured, already refunded, disputes, subscription state). The action audit needs read access only.
- Health check: Audon probes reads, and write permissions with ids that can’t exist (403 means no permission; 400 or 404 means the permission is there). Nothing is created. A read-only connector with a restricted key warns you when the key can write.
- Idempotency: every write carries
Idempotency-Key: audon_<action id>_<attempt>andmetadata[audon_action_id]/metadata[audon_attempt], which is how reconciliation finds an Unknown action later. - Verification: after a 2xx, Audon re-reads the object before it reports
completed.
Shopify
Connect Shopify store: enter your store’s *.myshopify.com domain, approve the Audon app in your Shopify admin, done. Audon uses the Admin GraphQL API (version 2026-10) with an expiring offline token for the store that it refreshes itself. One install asks for the read and write scopes; Audon only reads until you turn on protection. Stores connected earlier with read scopes only reconnect once (Reconnect to turn on protection).
| Action | Resource | Shopify | Scope |
|---|---|---|---|
refund.create | gid://shopify/Order/… | refundCreate to the original payment, no restock | write_orders |
order.cancel | gid://shopify/Order/… | orderCancel (refund, restock, notify params) | write_orders |
discount.create | gid://shopify/Customer/… | Single-use code for the customer (discountCodeBasicCreate), returned in the outcome | write_discounts |
credit.create | gid://shopify/Customer/… | Store credit (storeCreditAccountCredit), or a gift card for the customer when store credit isn’t granted (credit_method overrides) | write_store_credit_account_transactions or write_gift_cards |
- Read scopes for the audit and the business rules:
read_orders,read_discounts,read_gift_cards,read_customers,read_store_credit_accounts,read_store_credit_account_transactions. Shopify shows orders from the last 60 days unless the app also holdsread_all_orders. - Business rules: a refund must fit the order’s received amount minus refunds (and refunds in flight), the order must be paid, in the action’s currency and not disputed; a cancel needs an order that isn’t cancelled. Numeric ids are accepted and stored as GIDs, so duplicates match however the agent spells them.
- Idempotency: refunds use Shopify’s
@idempotent(key: "audon_<action id>_<attempt>")and carryaudon_action_id=… attempt=…in the refund note; cancellations carry it in the staff note; discount and gift card codes are derived from the action id, so a repeat can’t create a second one. - Unknown outcomes are looked up: refunds by the note on the order’s refunds, cancellations by
cancelledAt, discounts by code, gift cards by code and note, store credit by amount and time after the attempt (ambiguous matches stay Unknown). - Rate limits: Audon follows Shopify’s cost-based throttle and retries throttled requests with the same idempotency key.
- Data minimization: Audon reads ids, amounts, currencies, statuses, dates and its own notes. It never requests customer names, emails, phone numbers or addresses. It answers Shopify’s
customers/data_request,customers/redactandshop/redactwebhooks, andapp/uninstalleddisconnects the store.
Webhook: your endpoint executes
For any system without a built-in connector (an order system, a billing tool, an internal service), Audon sends the approved action to your endpoint, signed, with an idempotency key, and asks your status endpoint when an outcome is unclear.
Execute request
POST /audon/actions HTTP/1.1
Content-Type: application/json
Idempotency-Key: audon_act_8Rk4…_1
x-audon-action-id: act_8Rk4…
x-audon-signature: t=1793611323,v1=5f2c…
{ "id": "act_8Rk4…", "type": "order.cancel", "attempt": 1, "idempotency_key": "audon_act_8Rk4…_1",
"agent": "customer-support-agent", "resource": "order_8812", "customer": "cus_S8812k",
"amount_minor": "45000", "currency": "USD", "params": {} }The signature is v1 = hex(HMAC-SHA256(secret, "<t>.<raw body>")). Check it and the timestamp before you act.
Your answer
| You return | Audon records |
|---|---|
2xx { "status": "completed" | "failed" | "pending", "external_id"?, "message"? } | That status (pending = executing) |
| 4xx | failed (not done, safe to retry) |
| 5xx, 409, a redirect, a timeout, or a 2xx without a status | unknown, then reconciliation |
Treat a repeated Idempotency-Key as the same action
Your endpoint must deduplicate on the key: a second request with the same key returns the first result and does nothing new.
Status endpoint
GET /audon/status?idempotency_key=audon_act_8Rk4…_1&action_id=act_8Rk4… HTTP/1.1
x-audon-signature: t=1793611353,v1=… # signed over "<t>.<path?query>"
200 { "status": "completed" | "failed" | "pending" | "not_found", "external_id"?: "…" }
404 → not_foundHealth check and limits
- Health checks send
POST <url>with{ "type": "audon.ping" }andx-audon-probe: 1. Answer 2xx without executing anything. - https on port 443 to public IP addresses only, checked again at connect time (safe against DNS rebinding). No redirects. Timeout 1–30 s, default 10 s.
Sample data
Demo organizations have synthetic Stripe and Webhook connectors and can’t hold real credentials or connect real accounts.
Last updated