The event envelope
Every delivery has the same Stripe-style envelope. Thedata payload is event-specific:
Unique event id. Dedupe on this — delivery is at-least-once.
The event type. Switch on it to route the event.
Unix seconds when the event was created.
Event-specific payload.
order.notification carries the full order content; the lifecycle events (order.created, order.paid, order.cancelled) carry summary fields. See Webhook events for each payload, and fetch GET /v1/orders/{orderId} for authoritative current state.Event types
Subscribe only to what you act on. The live catalog is always atGET /v1/webhook_event_types:
| Type | When it fires |
|---|---|
order.validation_requested | Maple asks you to validate an order before notifying you |
order.notification | An order is handed to you to fulfill — the event you act on |
order.created | An order was created — a lifecycle signal for analytics, thinner than the notification |
order.paid | Payment settled (can be after the handoff) |
order.cancelled | The order was cancelled — stop fulfilling it |
store.provisioned | A location was provisioned to your app |
store.deprovisioned | A location was deprovisioned from your app |
store.status.changed | A connected location’s status changed |
menu.sync.completed | A menu sync completed for a location |
menu.sync.failed | A menu sync failed for a location |
webhook.test is also delivered on demand by the test endpoint, so you can verify a handler before any real traffic.
These are discrete events, not a status feed. Maple doesn’t send a webhook for every order status change — the
transitions you drive yourself (
accept, ready, complete) aren’t echoed back, and there’s no per-transition
event. For an order’s current state, read GET /v1/orders/{orderId}. See the Order
lifecycle.Subscribing
Response
notification_url must be public HTTPS — private and internal addresses are rejected. Manage subscriptions with GET, PATCH (update the URL, event types, or enabled/disabled status), and DELETE on /v1/webhook_subscriptions/{id}. Updating a subscription leaves its signing secret unchanged.
Multiple subscriptions
You can register more than one subscription. Every enabled subscription whoseevent_types include a fired event gets its own signed delivery, each with its own signing secret — so overlapping event_types across subscriptions are allowed. This lets you fan out by destination: for example, point order events at your fulfillment service and menu.sync.* events at a separate back-office endpoint. Replay follows the same routing and skips any subscription that already received the event.
Verifying the signature
Each delivery carries two headers:maple-webhook-id— the event id.maple-webhook-signature—t=<unix_seconds>,v1=<hex_hmac>.
Delivery guarantees
- At-least-once. The same event can arrive more than once. Dedupe on the envelope
idand make your handler idempotent. - Respond fast. Return a
2xxquickly, then do slower work asynchronously. Any non-2xx(or a timeout) counts as a failed delivery. - Order is not guaranteed. Don’t assume events arrive in the order they occurred; reconcile against the order resource when sequence matters.
Retries and auto-disable
Each event is delivered with up to 6 attempts — the first immediately, then with increasing backoff:| Attempt | Delay after previous |
|---|---|
| 1 | immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
2xx response (or a timeout — the per-attempt limit is 15 seconds) fails that attempt. An event that fails all 6 attempts counts as one fully-failed delivery. After 5 consecutive fully-failed deliveries — five separate events that each exhausted every attempt — the subscription is automatically disabled; a single successful delivery resets the counter to zero. Re-enable it with a PATCH setting status back to enabled once your endpoint is healthy, then replay anything you missed.
The event ledger
Every event is recorded, so a missed or failed delivery is recoverable.GET /v1/webhook_events— your recent events, most recent first (up to 50). Useful for reconciliation and debugging.GET /v1/webhook_events/{eventId}— a single event, including its fulldatapayload.POST /v1/webhook_events/{eventId}/replay— re-deliver the event to currently-matching subscriptions. Idempotent: subscriptions that already received it are skipped, so replaying is safe.
Testing your handler
webhook.test event and returns whether it was delivered and the HTTP status your endpoint returned:
2xx.
Checklist
Verify the HMAC signature on every delivery against the raw body, and reject stale timestamps.
Dedupe on the envelope
id; make handlers idempotent.Return
2xx fast; process asynchronously.Subscribe only to the event types you handle.
Monitor for auto-disabled subscriptions and replay from the ledger after an outage.