This page covers normal Shoppex event webhooks like
order:paid and subscription:created. If you build a DYNAMIC product with dynamic_webhook, read Dynamic product delivery instead.Setting up webhooks
1
Create an endpoint
Create an HTTP endpoint on your server that accepts
POST requests.2
Register the endpoint
Go to Settings → Webhooks → Add Endpoint and enter your URL.
3
Select events
Choose the event names you want, for example:
order:paidorder:cancelledsubscription:created
GET /dev/v1/webhooks/events.You can register webhooks through the dashboard or manage webhook subscriptions through the Developer API. The event payload is the same either way.
Developer webhooks must target your own HTTP(S) endpoint. For Discord notifications, use Notifications → Sales Alerts instead of a Discord webhook URL.
Order events
If a paid checkout reduces product stock, handle
order:paid or order:paid:product. Shoppex does not send product:stock as a second event for every purchase-driven stock decrease. Use product:stock for direct catalog stock updates, for example when you edit stock through the dashboard or API.Subscription events
Shoppex supports more event names than these two tables show. Examples include
order:created, order:updated, order:partial, order:disputed, subscription:trial:started, subscription:updated, subscription:renewed, subscription:upcoming, plus product, query, feedback, and affiliate events. See Webhook events or GET /dev/v1/webhooks/events for the full current list.Webhook payload
All webhooks follow this structure:Dashboard test deliveries use the same
event / data / created_at envelope as live deliveries. The values inside data are synthetic, but Shoppex signs the raw JSON body the same way as a real delivery.The top-level webhook
created_at field is a Unix timestamp. Nested timestamps inside data can be ISO 8601 strings.Order webhooks can include payment-context fields such as
exchange_rate, crypto_exchange_rate, crypto_gateway, and apm_method. These fields let you match and analyze payments without a follow-up invoice fetch in most cases.Headers
Each webhook request includes these headers:Signature verification
Always verify webhook signatures to confirm that a request came from Shoppex. New integrations must verifyX-Shoppex-Signature-V2. Shoppex signs ${deliveryId}.${timestamp}.${rawBody} with HMAC-SHA256. Your webhook handler must reject timestamps outside a 5-minute window.
{"event":"order:paid","data":{...},"created_at":1775764170}, not just the inner data object. Use the per-webhook secret from Settings → Webhooks for that endpoint.
Per-payment callbacks created with the webhook field on POST /dev/v1/payments use a different secret. Shoppex returns it once as webhook_secret in the payment creation response.
The v1 segment in X-Shoppex-Signature-V2 is a version marker, not the signature. Simple example: in v1,t=1775764170,h=abc..., verify only the h value.
Do not verify JSON.stringify(req.body) after you parse the request. Verify the raw body bytes from the incoming HTTP request instead.
Response handling
Return200 OK as soon as you receive the request, then process the event in a background job. A slow synchronous handler risks the 30-second timeout described below.
Shoppex can deliver the same webhook more than once. Use the X-Shoppex-Delivery header to detect duplicates, and make your fulfillment logic idempotent.
One invoice can produce more than one payment attempt over time. For example, a customer can retry a payment or switch gateways. Treat the Shoppex invoice ID and event type as the durable signal, not a single provider session. Mark an order fulfilled when Shoppex reports the invoice as paid, not when you first see a provider-specific session ID.
Always verify signatures in production to prevent spoofing, and always use an HTTPS endpoint.
Retry policy
If your endpoint returns an error (a non-2xx status) or times out, Shoppex retries the delivery automatically.
After the 5th failed attempt, Shoppex marks the webhook as failed. You can retry it manually from the dashboard.
Testing webhooks
Use the dashboard to send test events.1
Open webhook settings
Go to Settings → Webhooks.
2
Select your endpoint
Click your endpoint.
3
Send a test event
Click Send Test Event.
4
Choose an event type
Select an event type.
Test
order:* deliveries include the main live fields you usually integrate against, for example gateway, total, total_display, currency, exchange_rate, crypto_gateway, apm_method, customer_email, and product context.Migrating from the legacy signature
Some existing integrations still verify the legacyX-Shoppex-Signature header. Move them to X-Shoppex-Signature-V2, using the code sample in Signature verification above.
X-Shoppex-Signature-V2 brings two headers not shown in the headers table above.
Dynamic delivery webhooks send
X-Shoppex-Delivery-Id instead of X-Shoppex-Delivery. See Dynamic product delivery for the full dynamic delivery header set.1
Read the raw body
If your handler does not already do this, read the raw request body before you parse it as JSON.
2
Switch the verified header
Verify
X-Shoppex-Signature-V2 with the code sample above, instead of X-Shoppex-Signature.3
Check the timestamp window
Reject requests where
X-Shoppex-Timestamp falls outside a 5-minute window, as the code sample does.4
Remove the legacy check
Remove code that verifies
X-Shoppex-Signature or X-Shoppex-Unescaped-Signature.X-Shoppex-Signature and X-Shoppex-Unescaped-Signature headers carry a body-only HMAC-SHA512 signature, with no timestamp. Shoppex keeps both available during the migration period. The timestamp in X-Shoppex-Signature-V2 is what protects a migrated integration against replay.
Webhook events
Full list of event types and payload examples
Dynamic delivery
Deliver digital products in real time