Event types
Shoppex supports order, subscription, product, query, feedback, affiliate, and reseller webhooks. Event names use colons as separators, likeorder:paid.
When creating webhooks through the Dev API, send the exact event name, for example
order:paid. Wildcard patterns like invoice.* do not work. Fetch the full allowlist from GET /dev/v1/webhooks/events.These event payloads are not the same as the
dynamic_webhook callback used by DYNAMIC products. For that contract, see Dynamic product delivery.Supported event names
- Order events
- Subscription events
- Other events
| Event | Description |
|---|---|
order:created | Order created |
order:updated | Order updated |
order:partial | Partial payment received |
order:paid | Order fully paid |
order:cancelled | Order cancelled or expired |
order:disputed | Order dispute opened |
order:created:product | Order created with product payload |
order:updated:product | Order updated with product payload |
order:partial:product | Partial payment with product payload |
order:paid:product | Paid order with product payload |
order:cancelled:product | Cancelled order with product payload |
order:disputed:product | Disputed order with product payload |
order:manual_payment_pending | Manual payment review required |
order:item.delivered | Line item fulfilled with late content |
order:item.delivery_failed | Dynamic line item delivery failed |
For paid product purchases, subscribe to
order:paid or order:paid:product.
If that purchase reduces available stock, Shoppex does not send a separate product:stock event for the same checkout.order:item.delivered and order:item.delivery_failed report per-line-item fulfillment after payment. See Asynchronous and Manual Fulfillment for their payloads and recovery flow.Payload families
Invoice payload
These events use the same base invoice payload shape asorder:paid:order:createdorder:updatedorder:partialorder:paidorder:cancelledorder:disputedorder:manual_payment_pending
Invoice payload with products
These events use the same invoice payload plus theproducts array, like order:paid:product:order:created:productorder:updated:productorder:partial:productorder:paid:productorder:cancelled:productorder:disputed:product
Example payloads
order:paid
Triggered when an order/invoice is successfully paid.{
"event": "order:paid",
"data": {
"uniqid": "abc123def456",
"type": "PRODUCT",
"status": "COMPLETED",
"gateway": "STRIPE",
"total": 49.99,
"total_display": 49.99,
"currency": "USD",
"exchange_rate": 1,
"crypto_exchange_rate": 0,
"crypto_gateway": null,
"apm_method": "CARD",
"customer_email": "[email protected]",
"country": "US",
"quantity": 1,
"product_id": "prod_xyz",
"product_title": "Pro License",
"is_developer_invoice": false,
"created_at": "2026-01-15T09:10:00.000Z",
"updated_at": "2026-01-15T10:10:00.000Z"
},
"created_at": 1705318200
}
Dashboard simulation for
order:paid uses this same envelope shape and the same core fields, just with synthetic values.order:cancelled
Triggered when an order is cancelled or expires.{
"event": "order:cancelled",
"data": {
"uniqid": "abc123def456",
"type": "PRODUCT",
"status": "VOIDED",
"gateway": null,
"total": 49.99,
"total_display": 49.99,
"currency": "USD",
"exchange_rate": 1,
"crypto_exchange_rate": 0,
"crypto_gateway": null,
"apm_method": null,
"customer_email": "[email protected]",
"product_id": "prod_xyz",
"product_title": "Pro License",
"created_at": "2026-01-15T09:10:00.000Z",
"updated_at": "2026-01-16T09:03:20.000Z"
},
"created_at": 1705400600
}
order:paid:product
Same asorder:paid but includes full product details in the payload.{
"event": "order:paid:product",
"data": {
"uniqid": "abc123def456",
"type": "PRODUCT",
"status": "COMPLETED",
"gateway": "STRIPE",
"total": 49.99,
"total_display": 49.99,
"currency": "USD",
"exchange_rate": 1,
"crypto_exchange_rate": 0,
"crypto_gateway": null,
"apm_method": "CARD",
"customer_email": "[email protected]",
"product_id": "prod_xyz",
"product_title": "Pro License",
"products": [
{
"uniqid": "prod_xyz",
"title": "Pro License",
"description": "Full access to all features",
"price": 49.99,
"price_display": 49.99,
"currency": "USD",
"type": "SERVICE"
}
],
"created_at": "2026-01-15T09:10:00.000Z",
"updated_at": "2026-01-15T10:10:00.000Z"
},
"created_at": 1705318200
}
order:cancelled:product
Same asorder:cancelled but includes full product details.order:manual_payment_pending
Triggered when Shoppex is waiting for an offline or manual payment review.{
"event": "order:manual_payment_pending",
"data": {
"uniqid": "abc123def456",
"type": "PRODUCT",
"status": "PENDING",
"gateway": "MANUAL",
"total": 49.99,
"total_display": 49.99,
"currency": "USD",
"exchange_rate": 1,
"crypto_exchange_rate": 0,
"crypto_gateway": null,
"apm_method": null,
"customer_email": "[email protected]",
"country": "US",
"quantity": 1,
"product_id": "prod_xyz",
"product_title": "Pro License",
"is_developer_invoice": false,
"created_at": "2026-01-15T09:10:00.000Z",
"updated_at": "2026-01-15T09:20:00.000Z"
},
"created_at": 1705315200
}
| Event | Description |
|---|---|
subscription:trial:started | Trial started |
subscription:trial:ended | Trial ended |
subscription:created | Subscription created |
subscription:updated | Subscription updated |
subscription:renewed | Subscription renewed |
subscription:cancelled | Subscription cancelled |
subscription:upcoming | Upcoming renewal reminder |
subscription:trial:started:product | Trial started with product payload |
subscription:trial:ended:product | Trial ended with product payload |
subscription:created:product | Subscription created with product payload |
subscription:updated:product | Subscription updated with product payload |
subscription:renewed:product | Subscription renewed with product payload |
subscription:cancelled:product | Subscription cancelled with product payload |
subscription:upcoming:product | Upcoming renewal with product payload |
Payload family
These events use the same subscription payload shape assubscription:created:subscription:trial:startedsubscription:trial:endedsubscription:createdsubscription:updatedsubscription:renewedsubscription:cancelledsubscription:upcomingsubscription:trial:started:productsubscription:trial:ended:productsubscription:created:productsubscription:updated:productsubscription:renewed:productsubscription:cancelled:productsubscription:upcoming:product
Example payloads
subscription:created
Triggered when a new subscription starts.{
"event": "subscription:created",
"data": {
"id": "sub_abc123",
"status": "ACTIVE",
"gateway": "STRIPE",
"customer_id": "cust_xyz789",
"current_period_start": "2026-01-15T00:00:00.000Z",
"current_period_end": "2026-02-15T00:00:00.000Z",
"created_at": "2026-01-15T00:00:00.000Z"
},
"created_at": 1705314600
}
subscription:cancelled
Triggered when a subscription is cancelled.{
"event": "subscription:cancelled",
"data": {
"id": "sub_abc123",
"status": "CANCELLED",
"gateway": "STRIPE",
"customer_id": "cust_xyz789",
"current_period_start": "2026-01-15T00:00:00.000Z",
"current_period_end": "2026-02-15T00:00:00.000Z",
"created_at": "2026-01-15T00:00:00.000Z"
},
"created_at": 1705918200
}
subscription:renewed
Triggered when a subscription renews for a new billing period.{
"event": "subscription:renewed",
"data": {
"id": "sub_abc123",
"status": "ACTIVE",
"gateway": "STRIPE",
"customer_id": "cust_xyz789",
"current_period_start": "2026-02-15T00:00:00.000Z",
"current_period_end": "2026-03-15T00:00:00.000Z",
"created_at": "2026-01-15T00:00:00.000Z"
},
"created_at": 1707991800
}
| Event | Description |
|---|---|
product:created | Product created |
product:edited | Product updated |
product:stock | Product stock changed through a direct catalog/product update |
product:dynamic | Dynamic product webhook dispatched |
query:created | Support query created |
query:replied | Support query replied |
feedback:received | Feedback received |
affiliate:payout_requested | Affiliate payout requested |
reseller:enrolled | Customer became an active reseller |
reseller:application.created | Customer applied to the reseller program |
reseller:application.rejected | Reseller application rejected |
reseller:suspended | Reseller suspended |
reseller:order.completed | Wholesale reseller order paid and delivered |
reseller:tier.advanced | Reseller reached a higher discount tier automatically |
reseller:supplier_order.delivered | A sold item was bought automatically at your supplier and delivered |
reseller:supplier_order.failed | An automatic supplier purchase failed and the customer was refunded |
Payload notes
Invoice-context product payload
product:dynamic currently uses the same invoice-style payload family as the order events.
It is not the same as the direct dynamic_webhook delivery callback.Runtime-specific events
product:stock is for direct catalog stock changes, such as dashboard or API product edits.
For stock consumed by checkout, use the matching order event, usually order:paid:product.Reseller events
Four enrollment-lifecycle events share one payload family: a singlereseller object. They are
reseller:enrolled, reseller:application.created, reseller:application.rejected, and
reseller:suspended. reseller:order.completed, reseller:tier.advanced, and the two
reseller:supplier_order.* events each have their own shape, documented below.reseller:enrolled fires on all three enrollment paths (invite accepted, self-enrollment in
open mode, and merchant approval of an application). Reinstating a suspended reseller does not
send an event. There is no reseller:reinstated.The two reseller:supplier_order.* events belong to the reselling shop, not the supplier’s:
they tell you what happened when your own store auto-purchased a sold item from your supplier.The remaining supported event names on this page are listed as valid event values.
Dedicated public example payloads for product:created, product:edited, product:stock, query:created, query:replied, feedback:received, and affiliate:payout_requested are not expanded here yet.Example payload
product:dynamic
Triggered after Shoppex starts dynamic product delivery for an invoice-backed purchase. This webhook uses invoice context and is separate from the directdynamic_webhook delivery request.{
"event": "product:dynamic",
"data": {
"uniqid": "abc123def456",
"type": "PRODUCT",
"status": "COMPLETED",
"gateway": "STRIPE",
"total": 49.99,
"total_display": 49.99,
"currency": "USD",
"customer_email": "[email protected]",
"country": "US",
"quantity": 1,
"product_id": "prod_xyz",
"product_title": "Dynamic Role",
"is_developer_invoice": false,
"created_at": "2026-01-15T09:10:00.000Z",
"updated_at": "2026-01-15T10:10:00.000Z"
},
"created_at": 1705318200
}
reseller:enrolled
Triggered when a customer becomes an active reseller.reseller:application.created,
reseller:application.rejected and reseller:suspended carry the identical reseller object —
only status and the timestamp fields differ.{
"event": "reseller:enrolled",
"data": {
"reseller": {
"id": "019cb402-1111-7000-8000-000000000001",
"customer_id": "019cb402-2222-7000-8000-000000000002",
"email": "[email protected]",
"status": "ACTIVE",
"tier": {
"id": "019cb402-3333-7000-8000-000000000003",
"name": "Gold",
"discount_percent": 15
},
"application_note": null,
"lifetime_revenue": "0.00",
"lifetime_orders": 0
}
},
"created_at": 1753430400
}
tier is null when no tier is assigned yet. application_note is only populated for
application-mode enrollments. lifetime_revenue is a decimal string, lifetime_orders an
integer.reseller:order.completed
Triggered when a wholesale reseller order is paid from the reseller’s balance and delivered. Theitems array is the price snapshot frozen at order time. It is not re-derived from the
current tier or product prices.{
"event": "reseller:order.completed",
"data": {
"reseller": {
"id": "019cb402-1111-7000-8000-000000000001",
"email": "[email protected]",
"tier": {
"id": "019cb402-3333-7000-8000-000000000003",
"name": "Gold",
"discount_percent": 15
}
},
"order": {
"invoice_uniqid": "019cb402-4444-7000-8000-000000000004",
"total": "425.00",
"currency": "USD",
"items": [
{
"product_id": "019cb402-5555-7000-8000-000000000005",
"variant_id": null,
"quantity": 5,
"unit_price": "85.00",
"line_total": "425.00"
}
]
}
},
"created_at": 1753430460
}
reseller:tier.advanced
Triggered when an order completion pushes a reseller’s lifetime totals past a tier’s auto-advance threshold. This event only ever fires alongsidereseller:order.completed —
there is no other code path that advances a tier automatically. Note the flat shape: the
reseller is identified by reseller_id and email at the top level, not by a nested
reseller object.{
"event": "reseller:tier.advanced",
"data": {
"reseller_id": "019cb402-1111-7000-8000-000000000001",
"email": "[email protected]",
"previous_tier": {
"id": "019cb402-6666-7000-8000-000000000006",
"name": "Silver",
"discount_percent": 10
},
"new_tier": {
"id": "019cb402-3333-7000-8000-000000000003",
"name": "Gold",
"discount_percent": 15
},
"lifetime_revenue": "12500.00",
"lifetime_orders": 42
},
"created_at": 1753430461
}
previous_tier is null when the reseller had no tier before. discount_percent is a number
on this event, unlike the decimal strings used for money fields.reseller:supplier_order.delivered
Triggered when one of your products is fulfilled by an automatic wholesale purchase at your supplier and the codes reached your buyer. Fires on your own shop.{
"event": "reseller:supplier_order.delivered",
"data": {
"supplier_order_id": "019cb402-7777-7000-8000-000000000007",
"status": "DELIVERED",
"quantity": 2,
"delivered_quantity": 2,
"shortfall_quantity": 0,
"amount": "18.00",
"currency": "USD",
"failure_reason": null,
"retail_invoice": {
"uniqid": "019cb402-8888-7000-8000-000000000008",
"line_item_id": "019cb402-9999-7000-8000-000000000009"
},
"supplier_shop": {
"id": "019cb402-aaaa-7000-8000-00000000000a",
"invoice_uniqid": "019cb402-bbbb-7000-8000-00000000000b"
}
},
"created_at": 1753430470
}
amount is what was charged to your reseller balance at the supplier. A partial supplier
delivery still sends this event, with shortfall_quantity above zero.reseller:supplier_order.failed
Triggered when the automatic supplier purchase fails to deliver.status is REFUNDED when
the buyer was refunded and FAILED when no refund was possible. amount carries the refunded
sum or null. supplier_shop.invoice_uniqid is always null here, because no usable supplier
invoice exists.{
"event": "reseller:supplier_order.failed",
"data": {
"supplier_order_id": "019cb402-cccc-7000-8000-00000000000c",
"status": "REFUNDED",
"quantity": 1,
"delivered_quantity": 0,
"shortfall_quantity": 1,
"amount": "9.00",
"currency": "USD",
"failure_reason": "SUPPLIER_OUT_OF_STOCK: The supplier could not deliver this item.",
"retail_invoice": {
"uniqid": "019cb402-dddd-7000-8000-00000000000d",
"line_item_id": "019cb402-eeee-7000-8000-00000000000e"
},
"supplier_shop": {
"id": "019cb402-aaaa-7000-8000-00000000000a",
"invoice_uniqid": null
}
},
"created_at": 1753430480
}
failure_reason is a CODE: message string. Common codes are SUPPLIER_OUT_OF_STOCK,
ATTEMPTS_EXHAUSTED, and the guard failures for a disabled source, an inactive reseller
relationship, or a supply chain deeper than three shops.Common fields
All webhook payloads include these top-level fields:| Field | Type | Description |
|---|---|---|
event | string | Event type, for example order:paid |
data | object | Event-specific payload |
created_at | number | Unix timestamp when the event was created |
Top-level webhook
created_at is a Unix timestamp.
Nested timestamps inside data, like invoice created_at / updated_at or subscription period fields, are ISO 8601 strings when present.Webhooks
Setup, verification, and response handling
Dynamic delivery
Deliver products in real time through the webhook response