Skip to main content
Crave sends merchant events to server-side HTTPS endpoints configured in Business Manager → Developers → Webhooks. Sandbox and production are separate deployments: create and verify an endpoint in each environment that you use.

Delivery contract

Every request is an HTTP POST whose exact UTF-8 body is a versioned event envelope:
Crave includes these headers:

Verify signatures

Store the endpoint secret only in your server-side secret manager. Verify the signature against the raw request body before JSON parsing. The signed input is <timestamp>.<exact raw body>, using HMAC-SHA256 and unpadded base64url output.
Reject timestamps outside the 300-second tolerance. During a bounded secret-rotation overlap, Crave signs with both the current and previous secret, so a receiver deploying either valid secret continues to verify requests. After the new secret is deployed, remove the previous secret from the receiver.

Event catalog

The 2026-08-27 registry defines:
  • order.created
  • order.status_changed
  • order.cancelled
  • order.refunded
  • settlement.updated
  • payment.succeeded
  • payment.failed
  • catalog.published
  • catalog.availability_changed
  • location.updated
  • customer.verified
  • catering.event.updated
catering.event.updated carries only eventId, locationId, the six-digit display reference, change, and status. It never carries customer contact details, quote lines or prices, dietary/access notes, or customer-link credentials. Quote negotiation emits quote_sent, restaurant declined, and expired; the shared contract also reserves accepted and payment_received for the customer acceptance/payment lane. The display reference is not an authentication credential. Duplicate deliveries retain the same event ID. settlement.updated carries the order, fulfillment, settlement, refund, and reconciliation revisions side by side under revisions, alongside the orderId and the cartId the order was submitted from. Each revision advances independently, so reconcile the concern you care about against its own revision rather than inferring one from another. A pay-at-store order emits it while the settlement is still due, again as tender evidence arrives, and again for post-close recovery. Order lifecycle states are carried by order.status_changed; there are no separate order.confirmed, order.ready, or order.completed event types. cart.abandoned is not part of the outbound catalog. High-frequency shared-cart updates use the assisted-ordering realtime contract, not merchant webhooks. Order, payment, and settlement envelopes carry cartId so an assisted-ordering consumer can reconcile the exact canonical cart without scanning active sessions. It is null only when the order originated outside a Crave storefront cart, such as a provider-native POS order; consumers must not infer a cart in that case. For a cart-correlated event, use the signed locationId and cartId only as lookup coordinates, then read the canonical machine projection from GET /api/v1/locations/:locationId/carts/:cartId/commerce-projection. This server-to-server route requires an API key with orders:read and access to that location. It remains available after the guest cart capability expires, also covers payment.failed events that do not carry an order ID, and returns only the correlated cart ID, checkout attempt state, settlement state, reconciliation state, and order status: The generated Integration OpenAPI specification is also served by each API deployment at /integration-swagger.json. Its base is /api/v1, not /api/v1/storefront. Keep the organization API key on your server; a diner capability or merchant session is not a replacement. Private API errors use success, message, and an optional code/data, not the Storefront error envelope. Treat the projection as a reconciliation read, never permission to retry an uncertain checkout. Baseline middleware can reject before the handler: 429 returns {status, message} and a limiter-store outage returns 503 with {status, code, message} and Retry-After: 1. These responses do not carry success; the generated specification documents them separately from private handler errors.
Treat the webhook body as a hint. Confirm that the response cartId matches the event before updating local projections. The route is private, no-store; it never returns customer data, line items, raw provider evidence, or reusable cart credentials.
Every event in the registry is emitted except catalog.availability_changed and location.updated, which remain registry-reserved. order.created is emitted in the same transaction that submits a storefront cart as an order, payment.succeeded when that order’s online payment is captured, and settlement.updated for every settlement transition in every deployment. Subscribing to a reserved type is safe, but do not build a flow that assumes an event whose producer has not shipped.

Acknowledge and deduplicate

  1. Preserve the raw body and verify the timestamp and signature.
  2. Atomically record Crave-Webhook-Id in your database.
  3. If that ID already exists, return 2xx without repeating the business action.
  4. Queue your own processing and return 2xx promptly.
Delivery is at least once. Requests for different events may arrive out of order, and a timeout can occur after your server commits. Use the event ID for deduplication and use the Crave REST API to reconcile current resource state when the final outcome is ambiguous.

Retries and terminal failures

Crave retries network errors, 408, 409, 425, 429, and 5xx responses. Each automatic cycle allows up to 12 attempts, starts with a 30-second exponential-backoff window, applies full jitter, and caps the window at 6 hours. A valid Retry-After is honored up to 1 hour. Connections and responses each have a 10-second timeout. Other 4xx responses are terminal. Business Manager records each attempt’s status, duration, safe error code, allowlisted response headers, and at most 4 KB of response text. An organization administrator or authorized Crave support operator can manually redeliver a delivered or terminal request. Manual redelivery keeps the original event ID and exact body, records an audit reason, and opens one fresh bounded attempt cycle; it never creates a new business event.

Endpoint security

  • Endpoints must use public HTTPS on port 443.
  • Credentials in URLs, fragments, redirects, private/loopback/link-local destinations, and empty DNS answers are rejected.
  • DNS is revalidated immediately before every connection, and the connection is pinned to the validated address set to prevent DNS rebinding.
  • Signing secrets are encrypted at rest and shown only when an endpoint is created or rotated.
  • Disabling an endpoint terminalizes its queued deliveries; re-enable it before requesting a redelivery.
See the delivery timeline in Business Manager when troubleshooting. Crave staff use an audited cross-organization health view for queue age, failing endpoints, and terminal deliveries.

Validating payloads

Crave may add fields to an event payload within a contract version. If your handler validates with a strict schema — one that rejects unknown keys — an added field makes your endpoint answer 400, and a 400 is terminal: the delivery is dropped rather than retried, and no alert fires on our side because the request completed normally. Accept unknown fields, or track the registry and deploy your schema change before ours lands. If you correlate order and settlement events, Assisted Ordering documents which identifier each event is correlated by.