docs.checkout.webhooks

Webhooks & events

QuantaRoute delivers signed HTTP POST webhooks to your backend when checkout milestones occur. Event types depend on your payment mode.

Configure webhooks

Set your webhook URL and optional HMAC secret via checkout-admin. Use your merchant admin API key (x-api-key: dp_…) server-side only — never expose it in browser code.

bash
curl -X PATCH \
  "https://<project>.supabase.co/functions/v1/checkout-admin?action=webhooks" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_MERCHANT_ADMIN_KEY" \
  -d '{
    "webhook_url": "https://your-backend.com/webhooks/quantaroute",
    "webhook_secret": "your-random-hmac-secret"
  }'

Read current settings with GET checkout-admin?action=webhooks.

PATCH/checkout-admin?action=webhooksx-api-key

Update webhook config

Set webhook_url and webhook_secret for signed delivery.

request

json
{
  "webhook_url": "https://your-backend.com/webhooks/quantaroute",
  "webhook_secret": "your-random-hmac-secret"
}

HMAC verification

Each webhook delivery includes these headers when a secret is configured:

HeaderDescription
X-QuantaRoute-EventEvent type, e.g. session.completed or session.address_completed
X-QuantaRoute-TimestampISO 8601 timestamp of the event
X-QuantaRoute-SignatureHMAC-SHA256 of the raw request body, prefixed with sha256=
typescript
import crypto from 'crypto';

function verifyQuantaRouteWebhook(
  rawBody: string,
  signature: string | null,
  secret: string
): boolean {
  if (!signature?.startsWith('sha256=')) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature.slice(7)),
    Buffer.from(expected)
  );
}

// In your route handler:
// const event = req.headers.get('X-QuantaRoute-Event');
// const timestamp = req.headers.get('X-QuantaRoute-Timestamp');
// const signature = req.headers.get('X-QuantaRoute-Signature');
// verifyQuantaRouteWebhook(rawBody, signature, process.env.WEBHOOK_SECRET!)
Always verify the signature against the raw request body before parsing JSON. Reject requests with missing or invalid signatures.

Mode A events — external PG

When payment stays on your site (PayU, Cashfree, Paytm, Shopify), QuantaRoute does not fire session.completed.

EventWhenUse
session.address_completedVerified address ready; buyer about to leave widgetCreate draft order, reserve inventory
session.phone_verifiedPhone OTP succeededLink buyer identity
session.email_verifiedEmail OTP succeededLink buyer identity
session.completed is not sent in Mode A. Fire your own order-complete event after your PG confirms payment success. See Mode A payment docs.

Mode B events — BYO Razorpay

After successful prepaid or COD payment, checkout-payment fires session.completed.

session.completed is the primary order event for Mode B. Your endpoint receives JSON with payment details in the data object.

Prepaid payload

json
{
  "event": "session.completed",
  "merchant_id": "...",
  "buyer_id": "...",
  "session_id": "...",
  "auth_channel": "email",
  "timestamp": "2026-06-21T12:00:00.000Z",
  "data": {
    "payment_method": "razorpay",
    "razorpay_order_id": "order_...",
    "razorpay_payment_id": "pay_..."
  }
}

COD payload

COD completions omit Razorpay IDs and set payment_method: "cod".

json
{
  "event": "session.completed",
  "merchant_id": "...",
  "buyer_id": "...",
  "session_id": "...",
  "auth_channel": "email",
  "timestamp": "2026-06-21T12:00:00.000Z",
  "data": {
    "payment_method": "cod"
  }
}
This is QuantaRoute's merchant webhook (order lifecycle). It is separate from Razorpay Dashboard webhooks. Razorpay keys are used server-side by checkout-payment; you do not need Razorpay webhooks for the basic widget flow.

Test webhook delivery

Queue a test delivery to verify your endpoint and HMAC handling. The test event uses session.phone_verified with a test payload.

bash
curl -X POST \
  "https://<project>.supabase.co/functions/v1/checkout-admin?action=test_webhook" \
  -H "x-api-key: YOUR_MERCHANT_ADMIN_KEY"
POST/checkout-admin?action=test_webhookx-api-key

Test webhook

Queue a test webhook delivery to your configured webhook_url.

query parameters

NameRequiredDescription
actionYestest_webhook

response

json
{
  "success": true,
  "message": "Test webhook queued"
}

Debug failed deliveries

Inspect recent webhook delivery attempts — HTTP status, response body, and retry state — when debugging integration issues.

bash
curl "https://<project>.supabase.co/functions/v1/checkout-admin?action=webhook_deliveries" \
  -H "x-api-key: YOUR_MERCHANT_ADMIN_KEY"
GET/checkout-admin?action=webhook_deliveriesx-api-key

Webhook delivery log

List recent webhook delivery attempts for debugging.

query parameters

NameRequiredDescription
actionYeswebhook_deliveries
limitNoPage size (default 50).
offsetNoPagination offset (default 0).

Correlating sessions with orders

Recommended pattern for both modes:

  1. On session.address_completed or onComplete, create a draft order with quantaroute_session_id = sessionId.
  2. Pass your internal order_id to your PG as the payment reference.
  3. On PG success (Mode A) or session.completed (Mode B), look up the order and mark paid.
  4. Trigger fulfillment.