ThriveCart · AsyncAPI Specification

ThriveCart Event Subscriptions

Version 1

ThriveCart delivers account events to subscriber endpoints over HTTP POST. Two surfaces exist and they do not share event names. **Event Subscription API (this document).** Created programmatically with `POST https://thrivecart.com/api/external/subscribe`, taking at least `event` (an event key, or `*` for all) and `target_url`. Optional `trigger_fields` narrow delivery to specific products, bumps, upsells, downsells, affiliates or modes. Deliveries are **always JSON** in the request body. Removal is `POST /unsubscribe` with the endpoint `url`. **Account-wide webhooks (see x-legacy-webhooks).** Configured in the UI under Settings > API & Webhooks > Webhooks & Notifications, up to 5 destinations by default, delivered as `x-www-form-urlencoded` with a different, dotted event vocabulary. **Delivery identity.** Every event-subscription delivery carries `webhook_id`, a UUID that identifies that specific HTTP POST. It is stable across retries of the same delivery and is the documented idempotency key. `event_id` is retained for backward compatibility but is tied to the transaction/event record and may be absent on some event types. **Authenticity.** Payloads carry `thrivecart_secret` (the account's secret word) and `thrivecart_account`. There is no HMAC signature header and no timestamp, so replay protection is the consumer's responsibility. **Target URL restriction.** For OAuth applications, `target_url` must begin with a URL registered in the app's settings, the same way redirect URLs are registered. This does not apply to account-wide API keys.

View Spec View on GitHub CompanyCheckoutShopping CartPaymentseCommerceSubscriptionsAffiliate MarketingLearning ManagementCreator EconomyWebhooksAsyncAPIWebhooksEvents

Channels

order_created
order_payment_product
order_payment_bump
order_payment_upsell
order_payment_downsell
order_rebill
order_rebill_failed
order_rebill_completed
order_rebill_cancelled
order_refund_product
order_refund_bump
order_refund_upsell
order_refund_downsell
subscription_paused
subscription_resumed
cart_abandoned
affiliate_approved
affiliate_rejected
affiliate_commission_earned
affiliate_commission_payout
affiliate_commission_refund

Servers

https
subscriber
The consumer's own HTTPS endpoint, registered as target_url on POST /api/external/subscribe. ThriveCart is the publisher; there is no ThriveCart-hosted broker.

AsyncAPI Specification

Raw ↑
# Derived by API Evangelist from ThriveCart's own Event Subscription API documentation.
# Source: https://developers.thrivecart.com/documentation/event_subscription/intro/ and the
# 21 per-event pages linked from it, read 2026-08-12.
# ThriveCart publishes no AsyncAPI of its own. Every channel, event key and trigger field below
# is carried over from those pages; nothing is invented. Payload schemas are NOT documented by
# ThriveCart, so message payloads are left open (type: object) rather than guessed.
asyncapi: 3.0.0
info:
  title: ThriveCart Event Subscriptions
  version: '1'
  description: >
    ThriveCart delivers account events to subscriber endpoints over HTTP POST. Two surfaces
    exist and they do not share event names.


    **Event Subscription API (this document).** Created programmatically with
    `POST https://thrivecart.com/api/external/subscribe`, taking at least `event` (an event key,
    or `*` for all) and `target_url`. Optional `trigger_fields` narrow delivery to specific
    products, bumps, upsells, downsells, affiliates or modes. Deliveries are **always JSON** in
    the request body. Removal is `POST /unsubscribe` with the endpoint `url`.


    **Account-wide webhooks (see x-legacy-webhooks).** Configured in the UI under
    Settings > API & Webhooks > Webhooks & Notifications, up to 5 destinations by default,
    delivered as `x-www-form-urlencoded` with a different, dotted event vocabulary.


    **Delivery identity.** Every event-subscription delivery carries `webhook_id`, a UUID that
    identifies that specific HTTP POST. It is stable across retries of the same delivery and is
    the documented idempotency key. `event_id` is retained for backward compatibility but is tied
    to the transaction/event record and may be absent on some event types.


    **Authenticity.** Payloads carry `thrivecart_secret` (the account's secret word) and
    `thrivecart_account`. There is no HMAC signature header and no timestamp, so replay
    protection is the consumer's responsibility.


    **Target URL restriction.** For OAuth applications, `target_url` must begin with a URL
    registered in the app's settings, the same way redirect URLs are registered. This does not
    apply to account-wide API keys.
  contact:
    name: ThriveCart Developer Support
    url: https://developers.thrivecart.com/documentation/event_subscription/intro/
    email: support@thrivecart.com
  externalDocs:
    description: Event Subscription API
    url: https://developers.thrivecart.com/documentation/event_subscription/intro/
defaultContentType: application/json
servers:
  subscriber:
    host: '{target_url_host}'
    protocol: https
    description: >-
      The consumer's own HTTPS endpoint, registered as target_url on POST /api/external/subscribe.
      ThriveCart is the publisher; there is no ThriveCart-hosted broker.
    variables:
      target_url_host:
        description: Host of the subscriber endpoint. For OAuth apps it must match a URL
          registered in the application settings.
        default: example.com
components:
  messageTraits:
    thrivecartEvent:
      headers:
        type: object
        properties:
          Content-Type:
            type: string
            const: application/json
      payload:
        type: object
        description: >-
          ThriveCart does not publish payload schemas for event subscriptions. The fields below
          are the delivery-envelope fields it documents explicitly; the remainder of the body
          varies by event and is only observable at runtime.
        properties:
          webhook_id:
            type: string
            format: uuid
            description: UUID identifying this delivery. Stable across retries. Use as the
              idempotency key.
          event_id:
            type: string
            description: Legacy identifier tied to the transaction/event record. May be absent on
              some event types.
          event:
            type: string
            description: The event key that matched.
          mode_int:
            type: integer
            enum: [1, 2]
            description: 1 = test mode, 2 = live mode.
          thrivecart_account:
            type: string
            description: Account identifier.
          thrivecart_secret:
            type: string
            description: The account's secret word, for authenticity verification by the receiver.
        additionalProperties: true
channels:
  order_created:
    address: order_created
    messages:
      orderCreated:
        name: order_created
        title: Order created
        summary: An order is made. Triggers once per order; order_payment_product and siblings are
          usually the better choice.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
      description: 1 for test-mode purchases only, 2 for live-mode purchases only.
  order_payment_product:
    address: order_payment_product
    messages:
      orderPaymentProduct:
        name: order_payment_product
        title: Product purchased
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: base_product
      required: false
      type: numeric or array
      description: 'Numeric product ID, or array of product IDs. Example: 5 or [5, 19, 30].'
  order_payment_bump:
    address: order_payment_bump
    messages:
      orderPaymentBump:
        name: order_payment_bump
        title: Bump purchased
        summary: A bump's ID is the same as the product it is attached to.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.bump_id
      required: false
      type: numeric or array
    x-example-subscription: '{"event": "order_payment_bump", "target_url":
      "https://mysite.com/webhooks/123/", "trigger_fields": {"mode_int": 2, "purchase":
      {"bump_id": 5}}}'
  order_payment_upsell:
    address: order_payment_upsell
    messages:
      orderPaymentUpsell:
        name: order_payment_upsell
        title: Upsell purchased
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.upsell_id
      required: false
      type: numeric or array
  order_payment_downsell:
    address: order_payment_downsell
    messages:
      orderPaymentDownsell:
        name: order_payment_downsell
        title: Downsell purchased
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.downsell_id
      required: false
      type: numeric or array
  order_rebill:
    address: order_rebill
    messages:
      orderRebill:
        name: order_rebill
        title: Recurring payment made
        summary: Fires for a subscription or a split pay. Bumps do not support subscriptions.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
    - name: subscription.product_id
      required: false
      type: numeric
    - name: subscription.upsell_id
      required: false
      type: numeric
    - name: subscription.downsell_id
      required: false
      type: numeric
  order_rebill_failed:
    address: order_rebill_failed
    messages:
      orderRebillFailed:
        name: order_rebill_failed
        title: Recurring payment failed
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
    - name: subscription.product_id
      required: false
      type: numeric
    - name: subscription.upsell_id
      required: false
      type: numeric
    - name: subscription.downsell_id
      required: false
      type: numeric
  order_rebill_completed:
    address: order_rebill_completed
    messages:
      orderRebillCompleted:
        name: order_rebill_completed
        title: Subscription completed all payments
        summary: Split pay finished, or a subscription with a limited number of rebills. Fires at
          the same time as the final order_rebill.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
  order_rebill_cancelled:
    address: order_rebill_cancelled
    messages:
      orderRebillCancelled:
        name: order_rebill_cancelled
        title: Subscription cancelled
        summary: No further payments are due.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
  order_refund_product:
    address: order_refund_product
    messages:
      orderRefundProduct:
        name: order_refund_product
        title: Product refunded
        summary: Full or partial.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: base_product
      required: false
      type: numeric or array
  order_refund_bump:
    address: order_refund_bump
    messages:
      orderRefundBump:
        name: order_refund_bump
        title: Bump refunded
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.bump_id
      required: false
      type: numeric or array
  order_refund_upsell:
    address: order_refund_upsell
    messages:
      orderRefundUpsell:
        name: order_refund_upsell
        title: Upsell refunded
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.upsell_id
      required: false
      type: numeric or array
  order_refund_downsell:
    address: order_refund_downsell
    messages:
      orderRefundDownsell:
        name: order_refund_downsell
        title: Downsell refunded
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: purchase.downsell_id
      required: false
      type: numeric or array
  subscription_paused:
    address: subscription_paused
    messages:
      subscriptionPaused:
        name: subscription_paused
        title: Subscription paused
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
  subscription_resumed:
    address: subscription_resumed
    messages:
      subscriptionResumed:
        name: subscription_resumed
        title: Subscription resumed
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: mode_int
      required: false
      type: numeric
    - name: subscription.type
      required: false
      type: enum
      enum: [product, upsell, downsell]
  cart_abandoned:
    address: cart_abandoned
    messages:
      cartAbandoned:
        name: cart_abandoned
        title: Cart abandoned
        summary: A customer entered their email address on the cart page but left without
          purchasing.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: base_product
      required: false
      type: numeric or array
  affiliate_approved:
    address: affiliate_approved
    messages:
      affiliateApproved:
        name: affiliate_approved
        title: Affiliate approved for a product
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: product_id
      required: false
      type: numeric or array
  affiliate_rejected:
    address: affiliate_rejected
    messages:
      affiliateRejected:
        name: affiliate_rejected
        title: Affiliate rejected or access revoked
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: product_id
      required: false
      type: numeric or array
  affiliate_commission_earned:
    address: affiliate_commission_earned
    messages:
      affiliateCommissionEarned:
        name: affiliate_commission_earned
        title: Affiliate earned commission
        summary: Affiliate payouts only happen in live mode, so this never fires in test mode.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: affiliate_user_id
      required: false
      type: numeric or array
  affiliate_commission_payout:
    address: affiliate_commission_payout
    messages:
      affiliateCommissionPayout:
        name: affiliate_commission_payout
        title: Affiliate commission paid
        summary: Also fires for manual payouts. Live mode only.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: affiliate_user_id
      required: false
      type: numeric or array
  affiliate_commission_refund:
    address: affiliate_commission_refund
    messages:
      affiliateCommissionRefund:
        name: affiliate_commission_refund
        title: Affiliate commission refunded
        summary: Live mode only.
        traits: [$ref: '#/components/messageTraits/thrivecartEvent']
    x-trigger-fields:
    - name: affiliate_user_id
      required: false
      type: numeric or array
operations:
  receiveThriveCartEvent:
    action: receive
    channel:
      $ref: '#/channels/order_created'
    title: Receive a ThriveCart event subscription delivery
    summary: >-
      Subscribe with POST https://thrivecart.com/api/external/subscribe, body
      {"event": "<key>", "target_url": "<https url>", "trigger_fields": {...}}. Use "*" as the
      event key to receive every event, which is equivalent to creating a webhook in the account.
      Unsubscribe with POST /api/external/unsubscribe and the endpoint url.
x-legacy-webhooks:
  description: >-
    The UI-configured, account-wide webhook surface. Separate vocabulary, separate encoding.
    Documented at https://support.thrivecart.com/help/using-webhook-notifications/.
  configured_at: Settings > API & Webhooks > Webhooks & Notifications
  max_destinations: 5
  method: POST
  content_type: application/x-www-form-urlencoded
  activation_requirement: the endpoint must answer HTTP 2xx to both POST and HEAD during setup
  validation_field: thrivecart_secret
  events:
  - order.success
  - order.refund
  - cart.abandoned
  - order.subscription_payment
  - order.subscription_cancelled
  - order.subscription_paused
  - order.subscription_resumed
  - order.rebill_failed
  - affiliate.commission_earned
  - affiliate.commission_payout
  - affiliate.commission_refund
  - customer_updated
x-gaps:
- ThriveCart publishes no AsyncAPI, no JSON Schema and no field-level payload reference for any
  event. Only the delivery envelope fields are documented, so a consumer must observe a live
  delivery to learn the shape.
- Deliveries are not signed. Authenticity depends on a static secret echoed in the body, with no
  HMAC, no timestamp and no replay window.
- Retry behaviour is acknowledged ("if we retry the same delivery") but no schedule, backoff or
  maximum attempt count is published, and there is no delivery log or replay endpoint.
- The two event surfaces use different names for the same underlying facts (order_created vs
  order.success), which is a standing source of integration error.