Delivery contract
Every request is an HTTPPOST whose exact UTF-8 body is a versioned event envelope:
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.
Event catalog
The2026-08-27 registry defines:
order.createdorder.status_changedorder.cancelledorder.refundedsettlement.updatedpayment.succeededpayment.failedcatalog.publishedcatalog.availability_changedlocation.updatedcustomer.verifiedcatering.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.
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
- Preserve the raw body and verify the timestamp and signature.
- Atomically record
Crave-Webhook-Idin your database. - If that ID already exists, return
2xxwithout repeating the business action. - Queue your own processing and return
2xxpromptly.
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.
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 answer400, 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.