For the complete documentation index, see llms.txt. This page is also available as Markdown.

Webhooks overview

Webhooks let your systems react to events in your PeakCommerce tenant in near real time. This page is the developer reference; for the admin UI walk-through see the Webhooks page under Settings → Developer Tools. For the API to manage subscriptions see API reference: webhook subscriptions.

Architecture

PeakCommerce
   │  (event happens)

Webhook subscription      ── HMAC-signed POST ──▶ Your endpoint
   ▲                                                  │
   │                                       2xx within 10s
   │  (retry up to 5× on failure)                     ▼
   └────────────────────────────────────────  Delivered, recorded

Delivery format

Each delivery is a POST with Content-Type: application/json and this body:

{
  "event": "subscription.changed",
  "timestamp": "2026-05-02T14:01:23Z",
  "tenantId": "ten_01H...",
  "data": { /* the resource that changed */ }
}

Headers:

Header
Description

X-Webhook-Signature

sha256=<hex_hmac_sha256> — HMAC of the raw body (see below)

X-Webhook-Event

The event type (e.g. subscription.changed)

X-Webhook-Timestamp

ISO 8601 time of the event

Signature verification

Each subscription has a signing secret, returned once when you create it (POST /webhooks) — store it securely; it is never shown again.

The signature is HMAC-SHA256(secret, rawBody), hex-encoded, sent in X-Webhook-Signature with a sha256= prefix. Verify it over the raw request body (do not parse first), using a constant-time comparison:

Reject any request whose signature does not match, and confirm the tenantId in the body matches the tenant you expect.

Event types (selected)

The event field carries the event type. A selection:

Event
When

account.created, account.updated

Account CRUD

subscription.created, subscription.changed, subscription.cancelled, subscription.renewed

Subscription lifecycle

order.created, order.updated

Order lifecycle

payment.session_created, payment.succeeded, payment.failed

Payment lifecycle

invoice.created, invoice.paid, invoice.failed

Invoice lifecycle

webhook.test

Manually sent from the admin UI

The complete, live list is in GET /api/v1/manifest under capabilities.eventTypes.

Resolved entitlements on subscription events

Subscription events carry an extra subscription object holding the customer's resolved entitlement set, so you can react to subscription.created without a second call to the Entitlements API:

Two details worth reading carefully:

  • An absent subscription key is not the same as an empty one. entitlements: {} means the set resolved and this plan grants nothing. A missing subscription key means the set could not be resolved for this event — treat it as "unknown" and call the Entitlements API, rather than as "no entitlements". Gating to zero on a missing key would deny a paying customer their plan.

  • The same resolution rules as the API apply: null on a limit feature means unlimited, and resolvedFrom names the product the values came from (add-on products do not contribute).

Retries & dead-lettering

  • A delivery succeeds on any 2xx response within 10 seconds.

  • On failure (non-2xx, network error, or timeout) the delivery is retried up to 5 attempts total, with exponential backoff of 2^attempt seconds (≈2s, 4s, 8s, 16s between attempts).

  • After the 5th failed attempt the delivery is marked dead_letter and recorded under Admin → Webhooks → Deliveries.

  • List dead-lettered deliveries with GET /api/v1/webhooks/{id}/deliveries?status=dead_letter, and re-enqueue any of them with POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay.

Best practices

  • Respond quickly — return a 2xx within 10 seconds. Move slow work to a queue.

  • Be idempotent — deliveries may be retried, so process the same event safely more than once.

  • Verify the signature on every request.

  • Don't assume ordering — events may arrive out of order; use the resource's own updatedAt / timestamp as your watermark.

Last updated

Was this helpful?