Skip to main content

Webhooks

Webhooks notify your application when events occur in your store — such as order confirmations, payment completions, or low inventory alerts.

Setting Up

Create a webhook via the Admin API:
The response includes a secret for verifying webhook signatures. To subscribe to all events, use the wildcard *:

Event Types

Payload Format

Signature Verification

Every webhook delivery includes an X-Webhook-Signature header (HMAC-SHA256). Always verify this before processing.

Using the SDK helper

Manual verification

If you are not using the SDK, compute the signature yourself:
Always use crypto.timingSafeEqual instead of === for signature comparison. String equality is vulnerable to timing attacks.

Idempotency

HTTP Idempotency Keys

Use idempotency keys to safely retry POST requests without creating duplicate resources. Include an Idempotency-Key header with a unique value (UUID recommended).
Key rules:
  • Keys must be unique per request — use UUIDs
  • Keys are scoped to the store (API key)
  • Cached responses expire after 24 hours
  • Only successful responses (2xx) are cached
  • The Idempotency-Key header is optional. If omitted, the request is processed normally

Idempotent Webhook Processing

Webhooks may be delivered more than once (due to retries, network issues, or infrastructure failover). Your handler must be idempotent.
Database schema for deduplication:
Use a database transaction that inserts the event ID and performs the business logic atomically. This ensures that if processing fails, the event is not marked as handled and will be retried.

Retry Policy

Failed deliveries are retried with exponential backoff: After 5 consecutive failures, the webhook endpoint is marked as inactive and a notification is sent to the dashboard.

Fast response best practices

Return a 2xx response as quickly as possible. If your handler takes more than 30 seconds, the delivery will be considered failed and retried. Move heavy processing to a background queue.

Event Ordering

Events may arrive out of order. For example, order.paid might arrive before order.created due to network conditions.

Strategy: Use timestamps, not arrival order

If you receive an event for a resource that does not exist in your system yet:
  1. Store the event in a pending queue
  2. When the prerequisite event arrives (e.g., order.created), process it first
  3. Then replay any pending events for that resource

Queue-Based Processing

For production workloads, accept webhooks into a queue and process them asynchronously.

With Inngest

With BullMQ

Testing

Send a test event

Use the Admin API to send a test event to your webhook endpoint:
Or with the SDK:
The test endpoint sends a synthetic event with "test": true in the payload so you can distinguish test events from real ones.

Local development with ngrok

To receive webhooks on your local machine during development:
Remember to update or delete your development webhooks when you are done testing. Stale endpoints will accumulate failed deliveries and may be auto-deactivated.

Next Steps

Stripe Integration

Set up Stripe payments with webhook-driven confirmation.

TossPayments

Set up TossPayments with webhook-driven confirmation.

Recipes

Practical code recipes covering common commerce flows.

Error Handling

API error codes and recommended handling strategies.