Event delivery

Use Webhooks as Your Source of Truth

postMessage events make the browser feel instant. Signed webhooks tell your backend what actually happened, even if the buyer closes the tab.

Create an endpoint

Register an HTTPS endpoint and choose the events your backend can process. Store the returned signingSecret securely; it is shown once.

Create endpoint
curl -X POST https://api.usethrottle.dev/api/v1/webhook-endpoints \
  -H "x-api-key: $THROTTLE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "url": "https://shop.example.com/api/throttle/webhook",
    "enabledEvents": ["order.created", "payment.captured", "payment.failed"]
  }'

enabledEvents must be exact event-type strings from the catalog — Throttle uses payment.captured and subscription.cancelled, not Stripe-style payment.succeeded or subscription.expired. Fetch the full list from GET /api/v1/event-types. An unknown name is rejected with 400; the error’s details[].allowedValues enumerates every accepted event type.

Use /webhook-endpoints, not the legacy /webhooks
/api/v1/webhook-endpoints is the canonical, signed outbound webhook system documented on this page (enabledEvents, a whsec_ signing secret, X-Throttle-Signature, plus /deliveries, /replay, and /test). The older /api/v1/webhooks family (events, no signed delivery) is deprecated and no longer delivers events — its delivery worker has been decommissioned. Responses carry Deprecation + Sunset: 2026-10-11 headers; the routes will be removed after 2026-10-11. Migrate any integration still pointing at it to /api/v1/webhook-endpoints.

Verify signatures

Each delivery includes X-Throttle-Signature (format t=<unix_seconds>,v1=<hex>). Compute HMAC-SHA256 over <timestamp>.<raw body>. The verifier below also rejects deliveries whose timestamp falls outside a tolerance window (default 300s) so a captured delivery cannot be replayed indefinitely, and guards against a malformed v1 so a bad header returns false instead of throwing in your handler.

Node verifier
import { createHmac, timingSafeEqual } from 'node:crypto';

// Verify a Throttle webhook signature (header: "t=<unix_seconds>,v1=<hex>").
// For 24 hours after you rotate the endpoint's secret the header carries TWO
// v1 digests — outgoing secret first, new secret last — and any match
// verifies, so you can swap the secret in your config without a failed
// delivery. Rejects (returns false) when no digest matches OR the timestamp
// is outside the tolerance window — a replayed delivery is not accepted forever.
export function verifyThrottleWebhook(
  rawBody: string,
  header: string,
  secret: string,
  toleranceSeconds = 300,
): boolean {
  if (!header || typeof header !== 'string') return false;

  let ts = NaN;
  const digests: string[] = [];
  for (const kv of header.split(',')) {
    const idx = kv.indexOf('=');
    if (idx <= 0) continue;
    const k = kv.slice(0, idx).trim();
    const v = kv.slice(idx + 1).trim();
    if (k === 't') ts = Number.parseInt(v, 10);
    // Require hex — a malformed v1 would make a short Buffer and
    // timingSafeEqual would throw a RangeError, crashing your handler.
    else if (k === 'v1' && /^[0-9a-f]+$/i.test(v) && digests.length < 4) digests.push(v);
  }
  if (!Number.isFinite(ts) || digests.length === 0) return false;

  // Reject deliveries whose timestamp is too old (or too far in the future) to
  // stop indefinite replay.
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - ts) > toleranceSeconds) return false;

  const expected = Buffer.from(
    createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex'),
    'hex',
  );

  // Equal-length only, then a constant-time compare of every digest.
  let ok = false;
  for (const v1 of digests) {
    const received = Buffer.from(v1, 'hex');
    if (received.length === expected.length && timingSafeEqual(received, expected)) ok = true;
  }
  return ok;
}
Use the raw body
Signature checks fail if your framework parses and reserializes JSON before verification. Capture the raw request body first, then parse JSON after the signature passes.
Keep signature failures and schema failures apart
Verify the signature, then parse the envelope, and report the two failures with different status codes. If a strict schema rejects a field it has not seen and your handler answers with the same 401 it uses for a bad signature, a routine additive change looks like a rotated secret from the outside. That is exactly how an extension lost every delivery for hours on 2026-09-08 when environmentKind shipped. Throttle retries a 401 on the normal ladder; a 4xx that names a schema problem is far easier to find in the delivery log.

Rotate the signing secret

POST /api/v1/webhook-endpoints/:id/rotate-secret mints a new whsec_ and returns it once. For graceSeconds (default 86400, max 604800) every delivery is signed with both secrets — the header reads t=…,v1=<outgoing>,v1=<new> — so you can swap the secret in your config on your own schedule without a failed delivery. Send { "graceSeconds": 0 } to revoke the old secret immediately when it has leaked. The response carries previousSecretExpiresAt.

Check every v1 digest
The verifier above accepts the header if any digest matches your secret, which is what makes the window seamless. A verifier that keeps only the last v1 still works — it verifies from the moment you deploy the new secret, and rejects until then, exactly as before the window existed.

Process idempotently

Webhook delivery is at-least-once. Store each event id before applying side effects so retries do not double-fulfill, double-email, or double-book revenue.

Deduping on event id covers retries. It does not cover a genuine repeat: order.created fires exactly once per order, but every other order lifecycle event is at-least-once by design, and a repeat carries a new event id. Moving an order backwards is a supported merchant action, so fulfilled → processing → fulfilled sends order.fulfilled twice. That is deliberate — a merchant who rewinds and re-fulfils has usually re-shipped, and suppressing the second event would be the one case where a shipping notification must not go missing. Make handlers that must not act twice idempotent on the entity and target state, not on the event id alone.

Digital fulfillment can be automatic
If a paid order has line items marked fulfillmentType: 'digital' or fulfillmentType: 'access_grant', Throttle creates and completes those fulfillment rows after the order enters processing. Listen for fulfillment.completed and order.fulfilled in addition to payment events when you need to mirror delivery state.
Behaviour change 2026-08-24: shipment delivery

fulfillment.shipment.delivered now fires when the arrival is recorded — a call to POST /fulfillments/{id}/delivered — and no longer when the shipment fulfillment is completed. Completing a fulfillment is carrier handoff, so the old timing announced a delivery while the parcel was still moving. Merchants who complete a fulfillment and never call the new endpoint will not see this event at all; listen for fulfillment.completed if what you want is handover.

The payload gained the shipment object, so data.shipment.actualDelivery carries the arrival timestamp. The buyer-facing customer-order-delivered email follows this event, and so moved with it.

Recommended fields

  • event_id unique identifier from the delivery envelope.
  • event_type for routing and debugging.
  • event_version from the delivery envelope for payload migrations.
  • environment_id from the delivery envelope for environment-scoped processing.
  • processed_at timestamp after side effects finish.
  • payload raw JSON for audit and replay.

Event families

  • Cart (14 events)
  • Order (13 events)
  • Quote (9 events)
  • Payment (14 events)
  • Fulfillment (6 events)
  • Subscription (15 events)
  • Discount (2 events)
  • Customer (9 events)
  • AR / Net30 (1 events)
  • Imports (1 events)
  • Buyer-facing scripts (3 events)
  • Shipping & Tax (1 events)
  • Workspace payment methods (5 events)
  • Platform billing charges (2 events)
  • Workspace lifecycle (1 events)
  • Extension lifecycle (2 events)

Abandoned carts & cart lifecycle

Carts are authoritative in Throttle. When your storefront creates a native cart (POST /api/v1/carts), Throttle tracks its whole lifecycle and detects abandonment server-side — you don't build your own timer.

  • cart.abandoned — a nightly sweep marks an open cart abandoned once it sits idle past the application's configured threshold (or you can react immediately on delivery). Throttle also sends the buyer a customer.cart_abandoned recovery email when it can resolve an email and the app has recovery enabled — subscribe to the event only if you want to run your own follow-up.
  • cart.converted — fires when a cart becomes an order (the successful-checkout signal, alongside order.created / payment.captured). A cart that lapses past its expires_at window is swept into cart.abandoned — there is no separate cart.expired webhook.
These are cart.* events — there is no checkout.* namespace
Use cart.abandoned and cart.converted — not checkout.abandoned / checkout.expired / checkout.completed (which don't exist). Subscribing to any cart event requires the carts:read scope on your API key — a key without it won't see cart events in the subscribable list at all.

The cart.abandoned delivery carries the full cart so your follow-up needs no extra fetch — buyer, line items, totals, and a recoveryUrl that reopens the checkout:

cart.abandoned delivery
{
  "id": "evt_2b8f...",
  "type": "cart.abandoned",
  "workspaceId": "9c1e...",
  "createdAt": "2026-07-04T18:22:05.000Z",
  "data": {
    "cartId": "cart_9f2a...",
    "sequence": 7,
    "currency": "USD",
    "total": 8900,
    "itemCount": 2,
    "customer": { "id": "cus_51...", "email": "buyer@example.com", "firstName": "Bea" },
    "lineItems": [
      { "id": "li_1", "name": "Premium Widget", "quantity": 2, "unitPrice": 2999, "total": 5998 }
    ],
    "recoveryUrl": "https://checkout.usethrottle.dev/c/cart_9f2a..."
  }
}

Payload envelope

Every delivery is a JSON object with stable top-level fields and event-specific fields under data. The signed body is capped at 256 KiB; larger deliveries are marked failed before Throttle POSTs them.

Delivery body
{
  "id": "evt_01HZX...",
  "type": "payment.captured",
  "version": "1",
  "workspaceId": "6659b411-9cd7-40ac-9a73-1e7801d89f55",
  "environmentId": "b7e5a40e-8c0f-4d85-a726-2ff2967f4b52",
  "environmentKind": "production",
  "createdAt": "2026-05-06T10:00:00.000Z",
  "data": {
    "paymentId": "pay_01HZX...",
    "orderId": "ord_01HZX...",
    "amount": 12900,
    "capturedAmount": 12900,
    "authorizedAmount": 12900,
    "currency": "USD",
    "customerId": "cus_01HZX...",
    "subscriptionId": "sub_01HZX...",
    "customer": {
      "id": "cus_01HZX...",
      "email": "buyer@example.com",
      "firstName": "Ada",
      "lastName": "Lovelace",
      "phone": null,
      "externalId": "your-user-42",
      "externalCustomerId": null
    }
  }
}
  • Headers: X-Throttle-Signature, X-Throttle-Event-Id, X-Throttle-Event-Type, Content-Type: application/json.
  • Envelope: id, type, version, workspaceId, environmentId, environmentKind, createdAt, and data. environmentKind is production or non_production: if your destination is a live system, drop non_production deliveries in one check. A shared test environment delivers to the same endpoint, correctly signed, so nothing else distinguishes synthetic traffic from a real buyer's.
  • Additive fields are not a version bump. Throttle adds top-level envelope fields and fields under data without changing version. Each addition is announced in the changelog, but never in advance of the first delivery that carries it. Parse the envelope with a schema that ignores or strips unknown keys; a strict schema that rejects them will fail every delivery the moment a field is added. version changes only when an existing field is removed, renamed, or changes type, and never without notice.
  • Replays: a replayed delivery re-sends the same event — same id, same createdAt, same data. The send time is the t= in the signature header. Treat a repeated id as already handled; never re-date the event.
  • Amounts: all money fields are integer minor units, for example cents for USD.
  • Customer identity: every subscription.* event, and every payment.* event that resolves an order, carries a nested customer object so you can map the delivery to your own user without a follow-up GET /customers/{id}. Read customer.externalId for the id you set yourself — externalCustomerId is a separate per-connection mapping and is null for most integrations. Payment events also carry customerId and, for subscription-driven charges, subscriptionId. Treat customer as optional: it is omitted when the record cannot be resolved.

Event payload reference

Each event below uses the common envelope above. Route by type and read the event fields from data.

How the data object is shaped

data follows two shapes — check the exact fields for each event in the table below rather than assuming one form:

  • Entity lifecycle events nest the full entity under its name: data.order, data.payment, data.subscription, data.customer, data.fulfillment, data.paymentMethod, and data.workspace (for platform-billing events). On order.created, the order includes clientContext when attribution was captured at checkout — UTMs, click ids (gclid / fbclid / msclkid / ttclid), gaClientId / gaSessionId, fbp / fbc, landingPage, referrer, consent, and the server-stamped ipAddress / userAgent. See Track conversions .
  • Cart activity events (cart.*) are intentionally flat and lightweight — data.cartId, data.sequence, plus the changed fields — because they fire at high frequency and do not ship the full cart.
  • Non-entity signals carry flat scalars, not a nested entity: order.sync_failed, order.sync_conflict, payment.disputed, payment.dispute_cleared, payment.recorded, payment.expired, subscription.trial_blocked, and shipping_tax.provider_connection.unhealthy. For example payment.disputed sends data.paymentId (not data.payment).

Every order.* event embeds data.order.paymentStatus, one of pending, authorized, captured, partially_paid, partially_refunded, refunded, failed, voided, processing, disputed, or expired. The last three arrived with the in-flight payment work: processing is a payment the provider has not resolved yet (it used to read failed), disputed is derived from the payment's disputed boolean and outranks captured because a chargeback has a deadline, and expired is an authorization that lapsed before capture. partially_paid means money has been captured for this order, but less than the order total. Most commonly a deposit on a quote with deposit-and-balance terms, where the balance has not yet been collected. A comped order reads captured as well: order.comped waives the remaining balance, so nothing is owed even though no money arrived. Read data.compAmount to tell a waived order from a paid one.

Every event below carries an example delivery: the exact envelope your endpoint receives, with fixed ids and timestamps. It is the same bytes GET /api/v1/event-types returns under example and the same fixture POST /api/v1/webhook-endpoints/:id/test sends, so a mapper written against it is written against what ships.

Cart

  • cart.created — A native cart is created. { cartId, sequence, applicationId, customerId, currency }
    Example delivery
    cart.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 1,
        "applicationId": "test_store_1a2b3c08",
        "customerId": "test_cust_1a2b3c02",
        "currency": "USD"
      }
    }
  • cart.updated — Cart metadata, customer, notes, or addresses change. { cartId, sequence, changedFields }
    Example delivery
    cart.updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 2,
        "changedFields": [
          "shippingAddress"
        ]
      }
    }
  • cart.item_added — A line item is added to the cart. { cartId, sequence, itemId, name, quantity, unitPrice }
    Example delivery
    cart.item_added
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.item_added",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 3,
        "itemId": "test_item_1",
        "name": "Test item",
        "quantity": 2,
        "unitPrice": 500
      }
    }
  • cart.item_updated — A line item quantity or price changes. { cartId, sequence, itemId, quantity, unitPrice }
    Example delivery
    cart.item_updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.item_updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 4,
        "itemId": "test_item_1",
        "quantity": 3,
        "unitPrice": 500
      }
    }
  • cart.item_removed — A line item is removed from the cart. { cartId, sequence, itemId }
    Example delivery
    cart.item_removed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.item_removed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 5,
        "itemId": "test_item_1"
      }
    }
  • cart.shipping_selected — A buyer selects a shipping method. { cartId, sequence, methodId, displayName, rateAmount, currency }
    Example delivery
    cart.shipping_selected
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.shipping_selected",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 6,
        "methodId": "ground",
        "displayName": "Ground",
        "rateAmount": 799,
        "currency": "USD"
      }
    }
  • cart.shipping_cleared — A selected shipping method is cleared. { cartId, sequence }
    Example delivery
    cart.shipping_cleared
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.shipping_cleared",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 7
      }
    }
  • cart.discount_applied — A cart discount code is applied. { cartId, sequence, code, amount, type, discountTotal }
    Example delivery
    cart.discount_applied
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.discount_applied",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 8,
        "code": "TESTCODE",
        "amount": 500,
        "type": "fixed_amount",
        "discountTotal": 500
      }
    }
  • cart.discount_removed — A cart discount code is removed. { cartId, sequence }
    Example delivery
    cart.discount_removed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.discount_removed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 9
      }
    }
  • cart.tax_recomputed — Cart tax lines are recomputed or cleared. { cartId, sequence, lineCount }
    Example delivery
    cart.tax_recomputed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.tax_recomputed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 10,
        "lineCount": 2
      }
    }
  • cart.checkout_started — A cart moves into checkout. { cartId, sequence }
    Example delivery
    cart.checkout_started
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.checkout_started",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 11
      }
    }
  • cart.converted — A cart is converted into an order. { cartId, sequence }
    Example delivery
    cart.converted
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.converted",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 12
      }
    }
  • cart.abandoned — A cart is marked abandoned. { cartId, sequence, currency, subtotal, taxTotal, shippingTotal, discountTotal, total, itemCount, customer: { id: string | null, email, firstName, lastName, phone, externalId, externalCustomerId } | null, lineItems: [{ id, type, referenceId, name, quantity, unitPrice, subtotal, total, imageUrl }], shippingAddress: CartAddress | null, billingAddress: CartAddress | null, recoveryUrl: string | null }
    Example delivery
    cart.abandoned
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.abandoned",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 13,
        "currency": "USD",
        "subtotal": 5000,
        "taxTotal": 0,
        "shippingTotal": 0,
        "discountTotal": 0,
        "total": 5000,
        "itemCount": 1,
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": "+1 555 555 0123",
          "externalId": "ext_cust_demo",
          "externalCustomerId": "ext_cust_demo"
        },
        "lineItems": [
          {
            "id": "test_item_1",
            "type": "product",
            "referenceId": "SKU-TEST-1",
            "name": "Test item",
            "quantity": 2,
            "unitPrice": 2500,
            "subtotal": 5000,
            "total": 5000,
            "imageUrl": null
          }
        ],
        "shippingAddress": {
          "firstName": "Test",
          "addressLine1": "1 Market St",
          "city": "San Francisco",
          "stateProvince": "CA",
          "postalCode": "94105",
          "countryCode": "US"
        },
        "billingAddress": null,
        "recoveryUrl": "https://shop.example.com/cart?c=test_cart_1a2b3c05"
      }
    }
  • cart.merged — An anonymous cart is merged into a customer cart. { cartId, sequence, fromCartId, toCustomerId }
    Example delivery
    cart.merged
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "cart.merged",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cartId": "test_cart_1a2b3c05",
        "sequence": 15,
        "fromCartId": "test_cart_1a2b3c0b",
        "toCustomerId": "test_cust_1a2b3c02"
      }
    }

Order

  • order.created — An order is persisted. { order, fromCart?, sessionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    order.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "pending",
          "source": "throttle-test",
          "clientContext": {
            "utmSource": "newsletter",
            "utmMedium": "email",
            "gclid": "test_gclid",
            "gaClientId": "1234567890.1720000000",
            "consent": {
              "analytics": true,
              "marketing": true
            }
          }
        },
        "sessionId": "test_sess_1a2b3c0b",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.updated — An order status changes without reaching a terminal state. { order, status, previousStatus, action, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    order.updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "processing",
          "paymentStatus": "partially_paid",
          "source": "throttle-test"
        },
        "status": "processing",
        "previousStatus": "pending",
        "action": "PAYMENT_CAPTURED",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.fulfilled — Every deliverable line item on the order has been fulfilled. Fires on entering `fulfilled`, whether the engine derived it from fulfillment rows or a merchant set it by hand. { order, status, previousStatus, action, manual?, actor?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    order.fulfilled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.fulfilled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "fulfilled",
          "paymentStatus": "pending",
          "source": "throttle-test"
        },
        "status": "fulfilled",
        "previousStatus": "processing",
        "action": "FULFILLMENT_COMPLETE",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.cancelled — An order is cancelled. { order, status, previousStatus, action, reason?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    order.cancelled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.cancelled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "cancelled",
          "paymentStatus": "pending",
          "source": "throttle-test"
        },
        "status": "cancelled",
        "previousStatus": "pending",
        "action": "CANCEL",
        "reason": "Synthetic cancellation",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.closed — A fulfilled order is closed. { order, status, previousStatus, action, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    order.closed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.closed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "closed",
          "paymentStatus": "pending",
          "source": "throttle-test"
        },
        "status": "closed",
        "previousStatus": "fulfilled",
        "action": "CLOSE",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.comped — A merchant wrote off the order's remaining balance. Money already captured stays captured; no processor is contacted. { order, status, paymentStatus, previousPaymentStatus, compAmount, netCaptured }
    Example delivery
    order.comped
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.comped",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 0,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "captured",
          "source": "throttle-test",
          "compAmount": 100
        },
        "status": "pending",
        "paymentStatus": "captured",
        "previousPaymentStatus": "pending",
        "compAmount": 100,
        "netCaptured": 0,
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.comp_reversed — A comp is undone — the order owes what it owed again. { order, status, paymentStatus, previousPaymentStatus, compAmount, netCaptured }
    Example delivery
    order.comp_reversed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.comp_reversed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "pending",
          "source": "throttle-test",
          "compAmount": 0
        },
        "status": "pending",
        "paymentStatus": "pending",
        "previousPaymentStatus": "captured",
        "compAmount": 0,
        "netCaptured": 0,
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.held — An order is frozen operationally. Nothing about money or delivery changed — branch on onHold, not on the order status. { order, onHold, holdReason, previousHoldReason, heldBy, releasedBy }
    Example delivery
    order.held
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.held",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "pending",
          "source": "throttle-test",
          "onHold": true,
          "holdReason": "Fraud review",
          "heldBy": "user_synthetic"
        },
        "onHold": true,
        "holdReason": "Fraud review",
        "previousHoldReason": null,
        "heldBy": "user_synthetic",
        "releasedBy": null,
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.hold_released — A hold is lifted. previousHoldReason carries the reason the hold existed. { order, onHold, holdReason, previousHoldReason, heldBy, releasedBy }
    Example delivery
    order.hold_released
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.hold_released",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "pending",
          "source": "throttle-test",
          "onHold": false,
          "holdReason": null,
          "heldBy": null
        },
        "onHold": false,
        "holdReason": null,
        "previousHoldReason": "Fraud review",
        "heldBy": null,
        "releasedBy": "user_synthetic",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.sync_failed — Provider order writeback retries are exhausted. { mappingId, connectionId, externalId, attempts, error }
    Example delivery
    order.sync_failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.sync_failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "mappingId": "test_map_1a2b3c0b",
        "connectionId": "test_conn_1a2b3c0c",
        "externalId": "bc_order_1001",
        "attempts": 5,
        "error": "Synthetic provider writeback failure",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • order.sync_conflict — An inbound provider update conflicts with Throttle payment state. { externalStatus, throttleStatus, dimension }
    Example delivery
    order.sync_conflict
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "order.sync_conflict",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "externalStatus": {
          "paymentStatus": "captured"
        },
        "throttleStatus": "authorized",
        "dimension": "payment",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • return.created — A return / RMA is opened against an order. { returnId, orderId, status, reason?, restock, refundAmount, items }
    Example delivery
    return.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "return.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "returnId": "test_ret_1a2b3c0b",
        "orderId": "test_ord_1a2b3c00",
        "status": "requested",
        "reason": "no_longer_needed",
        "restock": true,
        "refundAmount": 100,
        "items": [
          {
            "lineItemId": "test_li_1a2b3c0c",
            "quantity": 1
          }
        ]
      }
    }
  • return.updated — A return transitions (approved / rejected / received / completed / cancelled). On completion refundPaymentId is set. { returnId, orderId, status, previousStatus, restock, refundAmount, refundPaymentId? }
    Example delivery
    return.updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "return.updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "returnId": "test_ret_1a2b3c0b",
        "orderId": "test_ord_1a2b3c00",
        "status": "approved",
        "previousStatus": "requested",
        "restock": true,
        "refundAmount": 100
      }
    }

Quote

  • quote.requested — A buyer or integration submits a quote request (RFQ). { quote, revision? }
    Example delivery
    quote.requested
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.requested",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "requested",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "api",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": null
      }
    }
  • quote.proposed — A quote revision is issued and proposed to the buyer. { quote, revision }
    Example delivery
    quote.proposed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.proposed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "proposed",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        }
      }
    }
  • quote.viewed — The buyer opens the quote link. Throttled to one delivery per revision per 6 hours. { quote, revision }
    Example delivery
    quote.viewed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.viewed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "proposed",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        }
      }
    }
  • quote.comment_added — A shared (non-internal) comment is added by either party. { quote, revision?, comment }
    Example delivery
    quote.comment_added
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.comment_added",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "proposed",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        },
        "comment": {
          "id": "test_qc_1a2b3c0d",
          "authorType": "buyer",
          "body": "Can you do Net-45 instead of Net-30?",
          "createdAt": "2026-09-10T12:00:00.000Z"
        }
      }
    }
  • quote.revision_requested — The buyer asks for changes instead of accepting the current proposal. { quote, revision }
    Example delivery
    quote.revision_requested
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.revision_requested",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "revision_requested",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        }
      }
    }
  • quote.declined — The buyer (or a rep, recording a decline) declines the quote. { quote, revision?, declinedReason? }
    Example delivery
    quote.declined
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.declined",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "declined",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        },
        "declinedReason": "Chose another vendor"
      }
    }
  • quote.accepted — The buyer accepts a quote (or a rep records a phone/email acceptance) and checkout begins. { quote, revision }
    Example delivery
    quote.accepted
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.accepted",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "accepted",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        }
      }
    }
  • quote.converted — The accepted quote completes checkout and its order now exists. { quote, orderId }
    Example delivery
    quote.converted
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.converted",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "converted",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        },
        "orderId": "test_order_1a2b3c0d"
      }
    }
  • quote.expired — The hourly expiry cron flips a proposed quote past its revision expiry; it can no longer be accepted. { quote, revision: null }
    Example delivery
    quote.expired
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "quote.expired",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "quote": {
          "id": "test_quote_1a2b3c0c",
          "quoteNumber": "Q-1042",
          "status": "proposed",
          "customerId": null,
          "customerEmail": "buyer@example.com",
          "buyerReference": "PO-2211",
          "source": "dashboard",
          "currency": "USD",
          "assignedMemberId": null,
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "createdAt": "2026-09-10T12:00:00.000Z"
        },
        "revision": {
          "id": "test_qrev_1a2b3c0b",
          "revisionNumber": 1,
          "state": "issued",
          "issuedAt": "2026-09-10T12:00:00.000Z",
          "expiresAt": "2026-09-24T12:00:00.000Z",
          "subtotal": 250000,
          "taxTotal": 0,
          "discountTotal": 0,
          "shippingTotal": 0,
          "total": 250000,
          "paymentTerms": {
            "mode": "net_terms",
            "netN": 30
          },
          "depositAmount": null
        }
      }
    }

Payment

  • payment.pending — A payment is created and waiting for authorization. { payment }
    Example delivery
    payment.pending
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.pending",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "payment": {
          "id": "test_pay_1a2b3c01",
          "orderId": "test_ord_1a2b3c00",
          "amount": 100,
          "currency": "USD",
          "status": "pending",
          "processor": "card-simulator"
        }
      }
    }
  • payment.authorized — A payment authorization succeeds. { payment }
    Example delivery
    payment.authorized
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.authorized",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "payment": {
          "id": "test_pay_1a2b3c01",
          "orderId": "test_ord_1a2b3c00",
          "amount": 100,
          "currency": "USD",
          "status": "authorized",
          "processor": "card-simulator"
        }
      }
    }
  • payment.processing — The provider has neither approved nor declined yet — a 3DS challenge, a redirect method, a bank debit still settling. A resolution event (payment.authorized, payment.captured or payment.failed) follows. { payment, processorStatus }
    Example delivery
    payment.processing
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.processing",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "payment": {
          "id": "test_pay_1a2b3c01",
          "orderId": "test_ord_1a2b3c00",
          "amount": 100,
          "currency": "USD",
          "status": "processing",
          "processor": "card-simulator"
        },
        "processorStatus": "buyer_approval_pending"
      }
    }
  • payment.captured — A payment capture succeeds (full or partial). { paymentId, orderId, amount, capturedAmount?, authorizedAmount?, currency, processor?, processorTransactionId?, metadata?, customerId, subscriptionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    payment.captured
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.captured",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "amount": 100,
        "currency": "USD",
        "processor": "card-simulator",
        "processorTransactionId": "test_txn_1a2b3c0b",
        "metadata": {
          "orderRef": "TEST-PO-1"
        },
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.failed — A processor reports a terminal payment failure or decline. { paymentId, orderId, amount?, currency?, code?, message?, errorCode?, errorMessage?, customerId, subscriptionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    payment.failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "code": "card_declined_test",
        "message": "Synthetic test failure (Card Simulator)",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.voided — A payment authorization is voided. { payment }
    Example delivery
    payment.voided
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.voided",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "payment": {
          "id": "test_pay_1a2b3c01",
          "orderId": "test_ord_1a2b3c00",
          "amount": 100,
          "currency": "USD",
          "status": "voided",
          "processor": "card-simulator"
        }
      }
    }
  • payment.expired — An authorization lapsed before it was captured. Emitted by our own hourly sweep, not by the provider — the money was never taken and the buyer must be charged again. { paymentId, orderId, authorizedAt }
    Example delivery
    payment.expired
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.expired",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "authorizedAt": "2026-09-10T12:00:00.000Z",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.recorded — Money that arrived outside Throttle (cash, bank transfer, cheque) was recorded by the merchant. Not a processor capture: excluded from billable GMV. { paymentId, orderId, amount, currency, method, reference, receivedAt }
    Example delivery
    payment.recorded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.recorded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "amount": 100,
        "currency": "USD",
        "method": "bank_transfer",
        "reference": "TEST-WIRE-1",
        "receivedAt": "2026-09-10T12:00:00.000Z",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.refunded — A full refund succeeds. { paymentId, orderId, refundedAmount, paymentAmount, currency, status?, processor?, gr4vyRefundId?, customerId, subscriptionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    payment.refunded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.refunded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "refundedAmount": 100,
        "paymentAmount": 100,
        "currency": "USD",
        "status": "refunded",
        "processor": "card-simulator",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.partially_refunded — A partial refund succeeds. { paymentId, orderId, refundedAmount, paymentAmount, currency, status?, processor?, gr4vyRefundId?, customerId, subscriptionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    payment.partially_refunded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.partially_refunded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "refundedAmount": 40,
        "paymentAmount": 100,
        "currency": "USD",
        "status": "partially_refunded",
        "processor": "card-simulator",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.refund_failed — A refund attempt fails. { paymentId, orderId, amount, currency, gr4vyRefundId?, errorCode?, errorMessage?, customerId, subscriptionId?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    payment.refund_failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.refund_failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "amount": 50,
        "currency": "USD",
        "gr4vyRefundId": "test_ref_1a2b3c0b",
        "errorCode": "refund_failed_test",
        "errorMessage": "Synthetic refund failure",
        "customerId": "test_cust_1a2b3c02",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • payment.vaulted — A checkout stores a reusable payment method. { customerId, paymentMethodId, gr4vyBuyerId, processor, checkoutSessionId, recurring? }
    Example delivery
    payment.vaulted
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.vaulted",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customerId": "test_cust_1a2b3c02",
        "paymentMethodId": "test_pm_1a2b3c03",
        "gr4vyBuyerId": "test_buyer_1a2b3c0b",
        "processor": "embedded",
        "checkoutSessionId": "test_sess_1a2b3c0c",
        "recurring": {
          "plan": "test-plan",
          "interval": "monthly"
        }
      }
    }
  • payment.disputed — A payment is marked disputed — a Net30 payment flagged in the dashboard, or an ingested Gr4vy card chargeback. { paymentId, reason, openedAt }
    Example delivery
    payment.disputed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.disputed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "reason": "product_not_received",
        "openedAt": "2026-09-10T12:00:00.000Z"
      }
    }
  • payment.dispute_cleared — A payment dispute is cleared — a Net30 dispute cleared in the dashboard, or a Gr4vy chargeback won/reversed. { paymentId }
    Example delivery
    payment.dispute_cleared
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "payment.dispute_cleared",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01"
      }
    }

Fulfillment

  • fulfillment.created — A fulfillment is created for an order. { fulfillment, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "shipment",
          "status": "pending"
        },
        "order": {
          "id": "test_ord_1a2b3c00"
        }
      }
    }
  • fulfillment.completed — A fulfillment is completed. { fulfillment, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.completed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.completed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "shipment",
          "status": "completed"
        },
        "order": {
          "id": "test_ord_1a2b3c00"
        }
      }
    }
  • fulfillment.cancelled — A fulfillment is cancelled. { fulfillment, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.cancelled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.cancelled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "shipment",
          "status": "cancelled"
        },
        "order": {
          "id": "test_ord_1a2b3c00"
        }
      }
    }
  • fulfillment.shipment.shipped — A shipment fulfillment receives its first tracking number — supplied at creation via POST /orders/{orderId}/fulfillments `shipment.trackingNumber`, or later via PATCH .../fulfillments/{id}/shipment. Fires once per shipment; later tracking edits do not re-fire it. { fulfillment, shipment: { trackingNumber, carrier, trackingUrl, serviceLevel, shippedAt, estimatedDelivery, ... }, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.shipment.shipped
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.shipment.shipped",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "shipment",
          "status": "processing"
        },
        "shipment": {
          "fulfillmentId": "test_ful_1a2b3c06",
          "carrier": "ups",
          "trackingNumber": "TEST-TRACKING-123",
          "trackingUrl": "https://www.ups.com/track?tracknum=TEST-TRACKING-123"
        },
        "order": {
          "id": "test_ord_1a2b3c00",
          "customerId": "test_cust_1a2b3c02"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • fulfillment.shipment.delivered — A shipment is recorded as arrived via POST /fulfillments/{id}/delivered. Since 2026-08-24 this is the arrival itself, not the completion of the fulfillment. { fulfillment, shipment, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.shipment.delivered
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.shipment.delivered",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "shipment",
          "status": "completed"
        },
        "shipment": {
          "fulfillmentId": "test_ful_1a2b3c06",
          "carrier": "ups",
          "trackingNumber": "TEST-TRACKING-123",
          "trackingUrl": "https://www.ups.com/track?tracknum=TEST-TRACKING-123",
          "shippedAt": "2026-05-20T00:00:00Z",
          "actualDelivery": "2026-05-23T00:00:00Z"
        },
        "order": {
          "id": "test_ord_1a2b3c00"
        }
      }
    }
  • fulfillment.digital.delivered — A digital fulfillment is marked completed (download/access ready). { fulfillment, digitalDelivery?, order: { id, customerId? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    fulfillment.digital.delivered
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "fulfillment.digital.delivered",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "fulfillment": {
          "id": "test_ful_1a2b3c06",
          "orderId": "test_ord_1a2b3c00",
          "type": "digital",
          "status": "completed"
        },
        "digitalDelivery": {
          "downloadUrl": "https://example.com/download/test",
          "expiresAt": null
        },
        "order": {
          "id": "test_ord_1a2b3c00"
        }
      }
    }

Subscription

  • subscription.created — A subscription is created. { subscription, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "created",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.activated — A trialing subscription becomes active. { subscription, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.activated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.activated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "activated",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.updated — Subscription plan, metadata, or cancel-at-period-end changes. { subscription, cancelAtPeriodEnd?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "updated",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.plan_changed — A subscription plan change is applied immediately (upgrade). { subscription, previous, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.plan_changed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.plan_changed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "active",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "previous": {
          "planReference": "starter",
          "amount": 2900
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.plan_change_scheduled — A downgrade is scheduled for the next interval. { subscription, pending, effectiveAt, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.plan_change_scheduled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.plan_change_scheduled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "active",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "pending": {
          "planReference": "starter",
          "planName": "Starter Monthly",
          "interval": "monthly",
          "amount": 2900
        },
        "effectiveAt": "2026-10-10T12:00:00.000Z",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.paused — A subscription is paused. { subscription, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.paused
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.paused",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "paused",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.resumed — A paused subscription is resumed. { subscription, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.resumed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.resumed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "resumed",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.cancelled — A subscription is cancelled. { subscription, reason?, atPeriodEnd?, lastError?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.cancelled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.cancelled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "cancelled",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "reason": "merchant_action",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.invoice_refunded — One of a subscription's billing cycles is refunded. `intent` says whether the subscription was also cancelled. { subscription, invoiceId, amountRefunded, fullyRefunded, intent: 'money_only' | 'refund_and_cancel' }
    Example delivery
    subscription.invoice_refunded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.invoice_refunded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "active",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "invoiceId": "test_subinv_1a2b3c0b",
        "amountRefunded": 2000,
        "totalRefunded": 2000,
        "fullyRefunded": true,
        "intent": "money_only",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.renewed — A renewal succeeds. { subscription, payment?, order?, freeRenewal?, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.renewed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.renewed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "active",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD",
          "currentPeriodStart": "2026-09-10T12:00:00.000Z",
          "currentPeriodEnd": "2026-10-10T12:00:00.000Z"
        },
        "payment": {
          "id": "test_pay_1a2b3c01",
          "orderId": "test_ord_1a2b3c00",
          "amount": 100,
          "currency": "USD",
          "status": "authorized",
          "processor": "card-simulator"
        },
        "order": {
          "id": "test_ord_1a2b3c00",
          "orderNumber": "TEST-1001",
          "total": 100,
          "currency": "USD",
          "status": "pending",
          "paymentStatus": "pending",
          "source": "throttle-test"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.past_due — The first renewal failure moves a subscription to past_due. { subscription, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.past_due
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.past_due",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "past_due",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD",
          "failureCount": 1
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.payment_failed — A renewal payment attempt fails. { subscription, attempt, nextRetryAt, lastError, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.payment_failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.payment_failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "past_due",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD",
          "failureCount": 1
        },
        "attempt": 1,
        "nextRetryAt": "2026-09-11T12:00:00.000Z",
        "lastError": "Synthetic renewal failure",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.backup_pm_used — A renewal's primary card declined and the buyer's backup card was charged instead. { subscription, payment?, backupPaymentMethod: { cardLastFour?, cardBrand? }, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.backup_pm_used
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.backup_pm_used",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscription": {
          "id": "test_sub_1a2b3c04",
          "customerId": "test_cust_1a2b3c02",
          "status": "active",
          "planReference": "test-plan",
          "interval": "monthly",
          "amount": 2000,
          "currency": "USD"
        },
        "backupPaymentMethod": {
          "id": "test_pm_1a2b3c0b",
          "cardBrand": "visa",
          "cardLastFour": "4242"
        },
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.create_failed — Auto-create from a recurring checkout intent fails after vaulting. { checkoutSessionId, customerId, paymentMethodId, gr4vyBuyerId, recurring, reason, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.create_failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.create_failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "checkoutSessionId": "test_sess_1a2b3c0b",
        "customerId": "test_cust_1a2b3c02",
        "paymentMethodId": "test_pm_1a2b3c03",
        "gr4vyBuyerId": "test_buyer_1a2b3c0c",
        "recurring": {
          "plan": "test-plan",
          "interval": "monthly"
        },
        "reason": "Synthetic subscription create failure",
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • subscription.trial_blocked — Trial-fraud protection downgrades a requested trial. { subscriptionId, customerId, paymentMethodId, reason, requestedTrialDays, customer: { id, email, firstName, lastName, phone, externalId, externalCustomerId } | null }
    Example delivery
    subscription.trial_blocked
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "subscription.trial_blocked",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "subscriptionId": "test_sub_1a2b3c04",
        "customerId": "test_cust_1a2b3c02",
        "paymentMethodId": "test_pm_1a2b3c03",
        "reason": "card_fingerprint_seen",
        "requestedTrialDays": 14,
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }

Discount

  • discount.applied — A discount is applied to a cart. { cart, code, cartId }
    Example delivery
    discount.applied
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "discount.applied",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cart": {
          "id": "test_cart_1a2b3c05",
          "discountTotal": 500,
          "total": 1500,
          "currency": "USD"
        },
        "cartId": "test_cart_1a2b3c05",
        "code": "TESTCODE"
      }
    }
  • discount.removed — A discount is removed from a cart. { cart, cartId }
    Example delivery
    discount.removed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "discount.removed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "cart": {
          "id": "test_cart_1a2b3c05",
          "discountTotal": 0,
          "total": 2000,
          "currency": "USD"
        },
        "cartId": "test_cart_1a2b3c05"
      }
    }

Customer

  • customer.created — A customer is created. { customer }
    Example delivery
    customer.created
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.created",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • customer.updated — A customer profile is updated. { customer }
    Example delivery
    customer.updated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.updated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • customer.deleted — A customer is deleted. { customer }
    Example delivery
    customer.deleted
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.deleted",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customer": {
          "id": "test_cust_1a2b3c02",
          "email": "buyer@example.com",
          "firstName": "Test",
          "lastName": "Buyer",
          "phone": null,
          "externalId": "test_ext_1a2b3c09",
          "externalCustomerId": "test_conn_1a2b3c0a"
        }
      }
    }
  • customer.payment_method_added — A customer payment method is added. { paymentMethod }
    Example delivery
    customer.payment_method_added
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.payment_method_added",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentMethod": {
          "id": "test_pm_1a2b3c03",
          "customerId": "test_cust_1a2b3c02",
          "processor": "embedded",
          "methodType": "card",
          "cardBrand": "visa",
          "cardLastFour": "1111"
        }
      }
    }
  • customer.payment_method_removed — A customer payment method is removed. { paymentMethod }
    Example delivery
    customer.payment_method_removed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.payment_method_removed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentMethod": {
          "id": "test_pm_1a2b3c03",
          "customerId": "test_cust_1a2b3c02",
          "processor": "embedded",
          "methodType": "card",
          "cardBrand": "visa",
          "cardLastFour": "1111"
        }
      }
    }
  • customer.registered — A buyer registers a storefront account. { customerId }
    Example delivery
    customer.registered
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.registered",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customerId": "test_cust_1a2b3c02"
      }
    }
  • customer.email_verified — A buyer verifies their storefront account's email address. { customerId }
    Example delivery
    customer.email_verified
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.email_verified",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customerId": "test_cust_1a2b3c02"
      }
    }
  • customer.password_changed — A buyer changes their storefront account password, via reset or account settings. { customerId, via: 'reset' | 'change' }
    Example delivery
    customer.password_changed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.password_changed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customerId": "test_cust_1a2b3c02",
        "via": "reset"
      }
    }
  • customer.sessions_revoked — All of a buyer's storefront sessions are revoked at once (logout-all, a password reset, or a merchant-initiated sign-out). { customerId, reason }
    Example delivery
    customer.sessions_revoked
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "customer.sessions_revoked",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "customerId": "test_cust_1a2b3c02",
        "reason": "logout_all"
      }
    }

AR / Net30

  • invoice.past_due — A Net30 invoice passes a dunning tick. { paymentId, orderId, invoiceNumber, daysPastDue, tickFired, dueDate, totalAmount, currency }
    Example delivery
    invoice.past_due
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "invoice.past_due",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "paymentId": "test_pay_1a2b3c01",
        "orderId": "test_ord_1a2b3c00",
        "invoiceNumber": "INV-TEST-1001",
        "daysPastDue": 7,
        "tickFired": 7,
        "dueDate": "2026-09-10T12:00:00.000Z",
        "totalAmount": 100,
        "currency": "USD"
      }
    }

Imports

  • import.completed — A bulk data import run (validate or commit) finishes. { importId, entityType, status, mode, rowsProcessed, rowsCreated, rowsUpdated, rowsSkipped, rowsFailed, startedAt, finishedAt }. When rowsFailed > 0, GET /api/v1/imports/{importId}/errors for the row-level report.
    Example delivery
    import.completed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "import.completed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "importId": "test_imp_1a2b3c0b",
        "entityType": "order",
        "status": "completed",
        "mode": "commit",
        "rowsProcessed": 100,
        "rowsCreated": 96,
        "rowsUpdated": 0,
        "rowsSkipped": 0,
        "rowsFailed": 4,
        "startedAt": "2026-09-10T11:59:00.000Z",
        "finishedAt": "2026-09-10T12:00:00.000Z"
      }
    }

Buyer-facing scripts

  • script.loaded — A script mounted successfully on a buyer-facing surface. HIGH VOLUME by nature — one per script per page load. Subscribe only if you actually want the firehose; script.blocked and script.error are the monitoring signals. { scriptId, sha256, surface, outcome, detail, sessionId }. `sha256` is the exact bytes that ran, so it can be matched against the script inventory.
    Example delivery
    script.loaded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "script.loaded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "scriptId": "1a2b3c0b-0000-4000-8000-000000000000",
        "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "surface": "checkout",
        "outcome": "loaded",
        "detail": {},
        "sessionId": "sess_1a2b3c0c000040008000000000000000"
      }
    }
  • script.blocked — A script resolved and was delivered, then was refused at mount. Read `detail.reason` — today the only value is `consent`, meaning the buyer had not granted the script's category. { scriptId, sha256, surface, outcome, detail: { reason }, sessionId }.
    Example delivery
    script.blocked
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "script.blocked",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "scriptId": "1a2b3c0b-0000-4000-8000-000000000000",
        "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "surface": "checkout",
        "outcome": "blocked",
        "detail": {
          "reason": "consent"
        },
        "sessionId": "sess_1a2b3c0c000040008000000000000000"
      }
    }
  • script.error — A script failed: its source would not load, its bytes did not match the pinned hash, it threw while mounting, or it tried to navigate its own frame. `detail.message` says which. { scriptId, sha256, surface, outcome, detail: { message }, sessionId }.
    Example delivery
    script.error
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "script.error",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "scriptId": "1a2b3c0b-0000-4000-8000-000000000000",
        "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "surface": "checkout",
        "outcome": "error",
        "detail": {
          "message": "sha256 mismatch: fetched bytes do not match the pinned hash"
        },
        "sessionId": "sess_1a2b3c0c000040008000000000000000"
      }
    }

Shipping & Tax

  • shipping_tax.provider_connection.unhealthy — A shipping or tax provider connection auto-disables after repeated failures (consecutive_failures reaches threshold). { connection_id, axis, provider, environment, environment_id, application_id, workspace_id, consecutive_failures, last_error_reason, last_error_detail, last_error_at, fallback_policy }
    Example delivery
    shipping_tax.provider_connection.unhealthy
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "shipping_tax.provider_connection.unhealthy",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "connection_id": "test_conn_1a2b3c0b",
        "axis": "shipping",
        "provider": "easypost",
        "environment": "production",
        "environment_id": "test_env_1a2b3c0c",
        "application_id": "test_app_1a2b3c0d",
        "workspace_id": "ws_example",
        "consecutive_failures": 5,
        "last_error_reason": "rate_limited",
        "last_error_detail": "API rate limit exceeded; connection auto-disabled",
        "last_error_at": "2026-09-10T12:00:00.000Z",
        "fallback_policy": "strict"
      }
    }

Workspace payment methods

  • workspace.payment_method.added — Internal-only — fired when a platform-billing payment method is attached to a workspace. { workspace, paymentMethod }
    Example delivery
    workspace.payment_method.added
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.payment_method.added",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "paymentMethod": {
          "id": "pm_sample",
          "brand": "visa",
          "lastFour": "4242",
          "expMonth": 12,
          "expYear": 2028
        }
      }
    }
  • workspace.payment_method.removed — Internal-only — fired when a platform-billing payment method is hard-deleted from the workspace. { workspace, paymentMethod }
    Example delivery
    workspace.payment_method.removed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.payment_method.removed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "paymentMethod": {
          "id": "pm_sample",
          "brand": "visa",
          "lastFour": "4242",
          "expMonth": 12,
          "expYear": 2028
        }
      }
    }
  • workspace.payment_method.default_changed — Internal-only — fired when the workspace primary (default) payment method changes. { workspace, paymentMethod, previousPaymentMethod? }
    Example delivery
    workspace.payment_method.default_changed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.payment_method.default_changed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "paymentMethod": {
          "id": "pm_sample",
          "brand": "visa",
          "lastFour": "4242",
          "expMonth": 12,
          "expYear": 2028
        }
      }
    }
  • workspace.payment_method.backup_set — Internal-only — fired when the workspace backup payment method is set or cleared. { workspace, paymentMethod }
    Example delivery
    workspace.payment_method.backup_set
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.payment_method.backup_set",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "paymentMethod": {
          "id": "pm_sample",
          "brand": "visa",
          "lastFour": "4242",
          "expMonth": 12,
          "expYear": 2028
        }
      }
    }
  • workspace.payment_method.backup_used — Internal-only — fired when the renewal or dunning charge succeeded on the backup PM after the primary failed. { workspace, primaryPaymentMethod, backupPaymentMethod, charge }
    Example delivery
    workspace.payment_method.backup_used
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.payment_method.backup_used",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "primaryPaymentMethod": {
          "id": "pm_primary_sample",
          "brand": "visa",
          "lastFour": "4242"
        },
        "backupPaymentMethod": {
          "id": "pm_backup_sample",
          "brand": "mastercard",
          "lastFour": "5454"
        },
        "charge": {
          "amountCents": 12500,
          "currency": "USD"
        }
      }
    }

Platform billing charges

  • workspace.platform_charge.succeeded — Internal-only — fired after a successful platform-billing charge (initial subscribe or renewal). { workspace, invoice, charge }
    Example delivery
    workspace.platform_charge.succeeded
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.platform_charge.succeeded",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "invoice": {
          "number": "INV-sample-001",
          "periodStart": "2026-04-23T00:00:00Z",
          "periodEnd": "2026-05-23T00:00:00Z"
        },
        "charge": {
          "id": "charge_sample",
          "amountCents": 10000,
          "currency": "USD"
        }
      }
    }
  • workspace.platform_charge.failed — Internal-only — fired after a platform-billing charge fails (initial or renewal). { workspace, charge, error }
    Example delivery
    workspace.platform_charge.failed
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.platform_charge.failed",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace"
        },
        "charge": {
          "id": "charge_sample",
          "amountCents": 10000,
          "currency": "USD"
        },
        "error": "Card was declined."
      }
    }

Workspace lifecycle

  • workspace.trial_expired — Internal-only — fired by trial-expiry-runner when a workspace trial lapses without conversion. { workspace, expiredAt }
    Example delivery
    workspace.trial_expired
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "workspace.trial_expired",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "workspace": {
          "id": "ws_sample",
          "name": "Sample Workspace",
          "slug": "sample"
        },
        "expiredAt": "2026-09-10T12:00:00.000Z"
      }
    }

Extension lifecycle

  • extension.uninstalled — An extension installation ends — a merchant uninstalls it, or staff take the extension down. Delivered to the uninstalled installation's own endpoint without a subscription, and to any subscribed endpoint. { installationId, extensionId, applicationId, uninstalledAt, reason }
    Example delivery
    extension.uninstalled
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "extension.uninstalled",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "installationId": "test_inst_1a2b3c0b",
        "extensionId": "test_ext_1a2b3c0c",
        "applicationId": "test_app_sample",
        "uninstalledAt": "2026-09-10T12:00:00.000Z",
        "reason": "merchant"
      }
    }
  • extension.webhook_secret_rotated — The signing secret of an installation's webhook endpoint was rotated. Delivered to that endpoint, signed with BOTH the outgoing and the new secret until previousSecretExpiresAt, so the extension can fetch the new secret from GET /api/v1/installations/:id/webhook-secret before the old one stops verifying. Never carries a secret. { installationId, extensionId, endpointId, rotatedAt, previousSecretExpiresAt }
    Example delivery
    extension.webhook_secret_rotated
    {
      "id": "1a2b3c07-0000-4000-8000-000000000000",
      "type": "extension.webhook_secret_rotated",
      "version": "1",
      "createdAt": "2026-09-10T12:00:00.000Z",
      "environmentId": "11111111-1111-4111-8111-111111111111",
      "environmentKind": "production",
      "workspaceId": "22222222-2222-4222-8222-222222222222",
      "data": {
        "installationId": "test_inst_1a2b3c0b",
        "extensionId": "test_ext_1a2b3c0c",
        "endpointId": "test_wep_1a2b3c0d",
        "rotatedAt": "2026-09-10T12:00:00.000Z",
        "previousSecretExpiresAt": "2026-09-11T12:00:00.000Z"
      }
    }

Event scope reference

Subscribing to an event requires holding the matching read scope. When you create or update a webhook endpoint (or register an extension), every event in the requested list is checked against the registering caller's scopes; any event you are not allowed to read returns 403 with error.code = "insufficient_scopes" naming the missing scope. See the API key scopes reference for the full scope catalog and grant rules.

Gated at registration, not per delivery
The scope check happens once, when the subscription is created or edited — webhook endpoints are not bound to a single API key, so deliveries are not re-checked per event. Grant the read scope for every family you intend to subscribe to before registering.

The full mapping is available as JSON at GET /api/v1/event-types — each entry is { type, readScope, trigger, dataShape, requiredDataKeys, example } — plus a top-level conventions object stating the units every payload uses (money is integer minor units, timestamps are ISO 8601 UTC) , so a build step can check its handlers against the live catalogue without scraping this page. Payload shapes for every event are also typed in the @usethrottle/webhook-types package: import the ThrottleEvent discriminated union of ThrottleEventEnvelope variants and narrow on type to get the exact data shape per event.

application_scripts:read

  • script.blocked
  • script.error
  • script.loaded

billing:read

  • workspace.payment_method.added
  • workspace.payment_method.backup_set
  • workspace.payment_method.backup_used
  • workspace.payment_method.default_changed
  • workspace.payment_method.removed
  • workspace.platform_charge.failed
  • workspace.platform_charge.succeeded
  • workspace.trial_expired

carts:read

  • cart.abandoned
  • cart.checkout_started
  • cart.converted
  • cart.created
  • cart.discount_applied
  • cart.discount_removed
  • cart.item_added
  • cart.item_removed
  • cart.item_updated
  • cart.merged
  • cart.shipping_cleared
  • cart.shipping_selected
  • cart.tax_recomputed
  • cart.updated

customers:read

  • customer.created
  • customer.deleted
  • customer.email_verified
  • customer.password_changed
  • customer.payment_method_added
  • customer.payment_method_removed
  • customer.registered
  • customer.sessions_revoked
  • customer.updated

discounts:read

  • discount.applied
  • discount.removed

extensions:read

  • extension.uninstalled
  • extension.webhook_secret_rotated

fulfillment_digital:read

  • fulfillment.digital.delivered

fulfillments:read

  • fulfillment.cancelled
  • fulfillment.completed
  • fulfillment.created
  • fulfillment.shipment.delivered
  • fulfillment.shipment.shipped

imports:read

  • import.completed

invoices:read

  • invoice.past_due

order_returns:read

  • return.created
  • return.updated

orders:read

  • order.cancelled
  • order.closed
  • order.comp_reversed
  • order.comped
  • order.created
  • order.fulfilled
  • order.held
  • order.hold_released
  • order.sync_conflict
  • order.sync_failed
  • order.updated

payment_disputes:read

  • payment.dispute_cleared
  • payment.disputed

payment_refunds:read

  • payment.partially_refunded
  • payment.refund_failed
  • payment.refunded
  • subscription.invoice_refunded

payments:read

  • payment.authorized
  • payment.captured
  • payment.expired
  • payment.failed
  • payment.pending
  • payment.processing
  • payment.recorded
  • payment.vaulted
  • payment.voided

quotes:read

  • quote.accepted
  • quote.comment_added
  • quote.converted
  • quote.declined
  • quote.expired
  • quote.proposed
  • quote.requested
  • quote.revision_requested
  • quote.viewed

shipping_tax:read

  • shipping_tax.provider_connection.unhealthy

subscriptions:read

  • subscription.activated
  • subscription.backup_pm_used
  • subscription.cancelled
  • subscription.create_failed
  • subscription.created
  • subscription.past_due
  • subscription.paused
  • subscription.payment_failed
  • subscription.plan_change_scheduled
  • subscription.plan_changed
  • subscription.renewed
  • subscription.resumed
  • subscription.trial_blocked
  • subscription.updated

Retries

Non-2xx responses and network failures are retried with delayed backoff and are visible in webhook delivery logs. Design handlers to return 2xx only after the event is durably stored or safely ignored as a duplicate.

The retry curve is fixed at [5m, 15m, 1h, 6h, 24h] (max five attempts). After the final attempt, deliveries are marked dead_letter and stop retrying automatically; an operator can replay them via POST /api/v1/webhook-deliveries/{deliveryId}/replay .

Failures the destination can never recover from skip the curve entirely and are marked dead_letter on the first attempt: a malformed URL, a non-HTTPS scheme, a hostname that does not resolve, a hostname that resolves to a private or link-local address, and a payload over the size limit. The reason is recorded on the delivery’s lastError; fix the endpoint URL and replay. A temporary DNS failure is not in this set and is still retried.

sequenceDiagram
  participant T as Throttle
  participant Q as Delivery Queue
  participant E as Your Endpoint
  participant Op as Operator
  T->>Q: emit event (e.g. payment.captured)
  Q->>E: attempt 1
  E-->>Q: 5xx / timeout
  Note over Q: wait 5m
  Q->>E: attempt 2
  E-->>Q: 5xx / timeout
  Note over Q: wait 15m
  Q->>E: attempt 3
  E-->>Q: 5xx / timeout
  Note over Q: wait 1h
  Q->>E: attempt 4
  E-->>Q: 5xx / timeout
  Note over Q: wait 6h
  Q->>E: attempt 5
  E-->>Q: 5xx / timeout
  Note over Q: wait 24h, max attempts reached
  Q->>Q: mark delivery dead_letter
  Op->>T: POST /api/v1/webhook-deliveries/{deliveryId}/replay
  T->>Q: requeue
  Q->>E: manual retry attempt
  E-->>Q: 2xx
  Q->>Q: mark delivered
Webhook delivery retry timeline with manual replay path.

Manage endpoints

Endpoints have three states: active, paused, and deleted. Pause stops dispatch without losing the subscription; delete is a soft remove that excludes the endpoint from the list and from future dispatch.

  • PATCH /api/v1/webhook-endpoints/{id} updates url, enabledEvents, or isActive. Send { "isActive": false } to pause and { "isActive": true } to resume.
  • DELETE /api/v1/webhook-endpoints/{id} soft-deletes the endpoint. Deleted endpoints cannot be recovered through the API; create a new one if you need to resubscribe.
  • GET /api/v1/webhook-endpoints returns both active and paused endpoints; deleted are excluded.
  • GET /api/v1/webhook-endpoints/coverage reports subscribable event types your application emitted that no active endpoint is subscribed to. A handler written for an event you never subscribed to simply never runs, and the delivery log cannot show that — it only records what was sent, so the gap is indistinguishable from the event never happening. Defaults to a 30-day window; pass ?days= (1–90) to widen it. Paused endpoints do not count as coverage. The same list appears on the webhooks page in the dashboard.
    Coverage response
    {
      "data": {
        "windowDays": 30,
        "unsubscribed": [
          {
            "type": "subscription.paused",
            "count": 12,
            "lastEmittedAt": "2026-07-27T09:24:11.000Z"
          }
        ]
      }
    }
order.completed is now order.fulfilled
order.completed was renamed to order.fulfilled when an order's lifecycle status absorbed its fulfillment state — nothing emits the old type any more. Endpoints that were subscribed to it have been migrated to order.fulfilled in place, so no action is needed and no deliveries were lost. The old name is accepted on write and dropped from what gets saved, like any other retired type (below), so an integration that still sends it in an enabledEvents array will not 400 — but it will not receive anything either. Subscribe to order.fulfilled.
Read-modify-write is safe across event retirements
enabledEvents replaces the whole list, so the usual way to add one subscription is to read the endpoint and send its current array back with the new type appended. If we have retired an event type since your endpoint was created, that stored value is still in the array we hand you — and write requests accept it rather than rejecting the round-trip. Retired types are dropped before anything is saved, and the response lists them under retiredEventsIgnored so the removal is visible rather than silent:
PATCH response
{
  "data": {
    "id": "wep_01HZX...",
    "enabledEvents": ["payment.captured", "subscription.updated"],
    "retiredEventsIgnored": ["cart.expired"]
  }
}
A request whose event list is entirely retired types is rejected with 400 no_deliverable_events — saving it would leave the endpoint subscribed to nothing at all.

Inspect deliveries

GET /api/v1/webhook-deliveries returns recent delivery attempts. Paginate via limit (1–200, default 50) and offset (default 0). Response shape is { data: { items, total, limit, offset, hasMore } } ; keep paging until hasMore is false.

Narrow the list with endpointId, status (one of pending, delivered, failed, dead_letter) and eventType (an exact event name, e.g. payment.failed). Filtering happens server-side, so status=failed returns every failed delivery across the whole result set rather than only those on the page you happened to load.

GET /api/v1/webhook-deliveries/{id} returns one delivery in full: the exact payload envelope that was signed and POSTed, its status, lastStatus/lastError, and a signatureScheme descriptor (header name, the t=…,v1=… format, and the signed {t}.{rawBody} string). Use it to debug signature verification without reverse-engineering the headers from live traffic.

This is the first place to look when something is not happening and nothing is erroring: it separates “never sent” from “sent, and your handler swallowed it”, which have identical symptoms and completely different fixes. It is also the right source for test fixtures — a mock that returns a friendlier shape than production makes tests pass while the integration is broken, so replay a captured payload rather than writing what you think the shape is. See Failures with no error.

Send a test event

POST /api/v1/webhook-endpoints/{id}/test fires a synthetic, signed delivery so you can verify reachability and signature handling. Omit the body to send a default payment.captured sample, or pass { "eventType": "subscription.renewed" } for a realistic per-event stub. To exercise your own handler logic (org lookup, subscription status updates), pass an eventType plus a data object — it is delivered verbatim as the envelope data instead of the built-in stub.