Skip to main content
Flow Payroll delivers every event at least once: an event can occasionally arrive more than once, but it is never silently lost. A delivery that is not acknowledged is retried until it succeeds or the schedule runs out, and nothing is dropped silently: every attempt is in the delivery log.

What counts as delivered

Your server must answer with a success status, any status from 200 to 299 (a “2xx” status), within 15 seconds. Fifteen seconds is ample for storing an event and answering; it is not meant for doing the work. Anything else is a failure and is retried:
  • any other status, including 3xx: redirects are never followed, so register the final URL;
  • no answer within 15 seconds, or no connection within 5;
  • a TLS error, such as an expired or self-signed certificate.
Answer quickly and do the work afterwards. See Best practices.

Retry schedule

This is the example schedule from the Standard Webhooks specification. Each wait varies by up to 20% either way. When a busy receiver fails many deliveries at once, this spreads the retries out so they do not all return at the same moment. The whole schedule covers about 75.6 hours (just over three days), long enough to ride out a weekend outage. If attempt 10 fails, the delivery is Failed and not retried again. You can still resend it at any time. Every attempt of the same delivery carries the same webhook-id and the same body. X-Flow-Delivery-Attempt says which attempt it is.

Answers that change what happens next

Ordering

By default deliveries are not ordered: events are sent as they happen, and a retry can arrive after a later event. Use timestamp to tell which came first, or fetch the latest state from resourceUrl. If you need strict order, create the endpoint with "ordering": "Fifo". Its deliveries then arrive one at a time, in the order the events happened. The cost is that a delivery your server keeps rejecting holds up every event behind it until it succeeds or runs out of retries, so only choose it if order matters more than speed.

Rate limits

Set rateLimitPerSecond (1 to 1,000) on an endpoint to cap how fast Flow Payroll sends to it. Deliveries over the limit wait, not fail. Remove the cap with PATCH /endpoints/{endpointId} and {"rateLimitPerSecond": null}.

When an endpoint keeps failing

  • Ten failures in a row pause deliveries to the endpoint for a minute, then for longer each time it happens again, up to 30 minutes. One delivery is tried after each pause, and when it succeeds everything resumes. Waiting deliveries do not use up their attempts.
  • A day of continuous failure sends an email, so someone can fix your receiver before it is disabled. It goes to the endpoint’s alert contacts, or else your organisation’s or account’s default alert contacts, or else the person who created the endpoint and the account owner. See Alert emails. You get one email for each run of failures.
  • Five days of continuous failure disable the endpoint. Its status becomes DisabledBySystem with statusReason failing_for_5_days, new events are recorded as Skipped, and the same people are emailed again.
To bring a disabled endpoint back, fix your receiver, then PATCH /endpoints/{endpointId} with {"status": "Active"}. It starts with a clean record. Then replay what it missed.

Operational events

Emails suit one organisation. If you run payroll for hundreds, you want to act on a failing endpoint in code: open a ticket, page whoever is on call, or re-enable it once it is fixed. Subscribe another endpoint to these events and Flow Payroll sends them to it:
  • Who receives them. For an organisation’s endpoint: that organisation’s other endpoints and your account-wide endpoints. For an account-wide endpoint: your other account-wide endpoints. Never the endpoint the event is about, because it is the one that cannot receive it.
  • What they carry. The endpoint’s id, URL and description, organisationId, customerId, failingSince, the last status code and error token, and metadata.resourceUrl pointing at the endpoint (or, for an exhausted delivery, the delivery). Fields that do not apply are null.
  • They never cascade. If the endpoint receiving these events fails too, its failures are emailed as usual but raise no further operational events.
Subscribe with the exact names, or with webhook.* for all three. They are recorded, listed and replayable like any other event.

Pausing an endpoint yourself

PATCH /endpoints/{endpointId} with {"status": "Paused"} stops deliveries while you work on your receiver. Events that happen meanwhile are recorded as Skipped, not queued. Set the status back to Active and replay the window with "statuses": ["Skipped"] to receive them.

Delivery statuses