Delivery and Retries
What Your Endpoint Must Do
- Answer with any
2xxstatus (for example200or204) within 10 seconds. A2xxmeans "received"; Mekari POS does not read your response body. - Verify the signature first (see Verifying Signatures), then save the event and answer. Do slow work, such as calling the API or updating other systems, later in a background job.
- Answer every attempt the same way, also for an event you already received: answer
2xxand skip the work.
A delivery is one event sent to one endpoint. Each delivery is tried until it gets a 2xx or the rules below give up.
Retries
| Attempt | Sent about this long after the previous attempt failed |
|---|---|
| 1 | Right away, when the event happens |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 30 minutes |
| 6 | 1 hour |
| 7 | 3 hours |
| 8 | 6 hours |
After 8 attempts (about 11 hours after the first) the delivery fails for good. Times are approximate: a retry can start up to about a minute later than the table says.
| Your endpoint's answer | What happens |
|---|---|
2xx | Delivered. No more attempts. |
| No answer: connection or TLS error, or no answer within 10 seconds | Retried |
408, 429 or any 5xx | Retried |
Any 3xx | Fails for good at once. Redirects are never followed. |
Any other 4xx (for example 400, 401, 404) | Fails for good at once |
Retry-After. With a retried status, you can send a Retry-After header in seconds (for example Retry-After: 120) to wait longer before the next attempt. It can only make the wait longer than the table, never shorter, and at most 1 hour. A date value is ignored.
To ask for a retry, answer 503, not 4xx. A 4xx other than 408 and 429 is never retried.
Pausing
When 10 deliveries in a row fail for good, the endpoint is paused:
GET /webhooks/endpointsshows it withstatus: paused.consecutive_failuresshows the current count.- Nothing is sent to it while it is paused, and its waiting retries are cancelled. Events that happen while it is paused are not kept.
- Any delivered event (
2xx) resets the count to0. Most failures caused on the Mekari POS side, for example an event body that could not be built, do not count.
To resume, fix your receiver, check it with POST /webhooks/endpoints/{key}/test, then send the same PUT /webhooks/endpoints/{key} again. The endpoint becomes active, the count goes back to 0, and new events are sent from then on. test alone does not resume a paused endpoint. Then catch up on what you missed.
DELETE stops an endpoint on purpose and cancels its waiting deliveries. Setting it again later issues a new secret.
Order and Duplicates
Delivery is at least once, and in no fixed order.
- Duplicates happen. A network error after your endpoint saved an event can cause a retry. Save each event's
id(also sent asX-Mekari-Event-ID) and skip anidyou already processed. Theidis the same on every retry. - Order is not guaranteed. A retry can arrive after a newer event, and sales made offline in the cashier app arrive late. Use
occurred_atto order events about the same order or product, and for kitchen events also comparekitchen_status. When in doubt, read the current state withGET.
Catching Up After an Outage
There is no API to send past events again. After your receiver was down, a delivery failed for good, or the endpoint was paused, read the current data from the API:
- Orders:
GET /ordersfor each outlet, withsold_at_fromandsold_at_tocovering the gap. Start a little before the gap, because sales made offline can carry an earlier time. - Returns, refunds and exchanges:
GET /returns,GET /refundsandGET /exchangesfor each outlet, newest first. Theorder_idfilter works on all three lists, for exampleGET /returns?order_id=. - Products:
GET /products. - Collections:
GET /collections.
Then compare with what you have and update your records. Events that arrive later are still valid; drop the ones you already handled by id.