Swoop Developers

Webhooks

Your POS reports order status to Swoop by posting a webhook to the adapter. This page covers the endpoint, how your payload becomes a StatusEvent, and the acknowledgement contract that controls redelivery.

Endpoint

POST /webhook/{integration}/{locationId}?token=YOUR_WEBHOOK_TOKEN

Translation

The adapter is fully provider-agnostic — no POS-specific strings live in the core. It hands your raw webhook to your provider's WebhookTranslator:

TranslateWebhook(headers map[string]string, body []byte) (*canonical.StatusEvent, error)

Three outcomes:

You return Adapter does HTTP
a *StatusEvent applies it to the member's order (persist + live publish) 200 (or 500 if applying fails transiently)
nil, nil treats it as "not a status change I map" — ignores 200
nil, err treats the payload as poison — drops it 200

This is also where you verify any HMAC/signature header before trusting the body.

Acknowledgement & redelivery

The response status code is your POS's redelivery signal:

Response Meaning Your POS should
200 Accepted, or intentionally ignored/dropped stop redelivering
401 Bad/missing token fix auth, resend
500 Transient failure applying the status redeliver

The deliberate design choice: poison payloads are acked (200), not nacked. A webhook the adapter can't parse will never be fixed by redelivery, so it's dropped rather than looped forever. Only transient failures (e.g. a momentary write error) return 500 to invite redelivery — and because status application is keyed on the Swoop order id, redelivery is safe.

Example

A POS "order ready" webhook (illustrative shape):

POST /webhook/my-pos/51?token=••• HTTP/1.1
Content-Type: application/json

{
  "eventType": "order.updated",
  "order": { "thirdPartyReference": "128277", "status": "READY" }
}

Your translator maps this to:

{ "swoopOrderId": "128277", "status": "ready", "providerOrderId": "POS-55012" }

Swoop then moves the member's order to ready for pickup or ready for delivery based on the order's fulfillment.