---
title: "Action connectors: Stripe, Shopify and Webhook · Audon"
description: "Stripe and Shopify in one click (or a Stripe restricted key), and the Webhook connector contract: execute, status, signatures and idempotency."
url: https://audon.ai/docs/action-control/connectors
last_updated: 2026-11-02
---
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>` and `metadata[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 holds `read_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 carry `audon_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/redact` and `shop/redact` webhooks, and `app/uninstalled` disconnects 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

httpPOST <your url>

```
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

httpGET <status url>

```
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_found
```

### Health check and limits

- Health checks send `POST <url>` with `{ "type": "audon.ping" }` and `x-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 2 November 2026
