RevoplyAIDocs
Flow triggers

Responses and errors

The JSON every flow trigger request is answered with, every status it can carry, and which ones to retry.

Every answer from a flow trigger URL has the same JSON body, whatever its HTTP status:

{ "id": "8f14e45f-ceea-467a-9575-5b1e2c7d3a90", "status": "accepted", "detail": null }
FieldTypeMeaning
idUUID or nullThe run the request started, or, for a repeat, the run the first request started. null when nothing started.
statusstringaccepted, duplicate, or why not. Branch on this.
detailstring or nullWhy, in words for people, such as No phone number at "customer.phone". Log it; it may change.

The one exception: when one IP address sends more than 120 requests a minute to flow trigger URLs, it is answered 429 with the plain-text body Too many requests. Treat any 429 without JSON as rate_limited.

Every status

Generated from the list the API itself answers with:

statusHTTPRetryMeaningWhat to do
accepted202—The flow was queued for the customer the body names. id is the run.Done. Keep id to match the flow.completed or flow.failed event.
duplicate200—A request with this Idempotency-Key already started a run; nothing new was queued. id is that run.Treat as success: id is the run the first request started.
invalid_json400NoThe body is not JSON.Fix the body. The same request fails the same way every time.
idempotency_key_too_long400NoThe Idempotency-Key header is longer than 200 characters.Send a key of at most 200 characters.
not_in_plan403NoThe account's plan does not include automations, the developer API or automated templates.Stop sending. Nothing starts until the account's plan includes it.
not_found404NoNo hook has this token. It may have been regenerated or deleted.Check the URL: it may have been replaced or the flow deleted.
flow_off409NoThe flow is not published, is switched off, or is beyond the plan's number of flows.Publish the flow and switch it on, then send again.
flow_not_listening409NoThe published flow is not started by its webhook.Set the published flow's trigger to "Your system sends an event", then send again.
channel_unavailable409YesThe flow's WhatsApp number is not connected.Reconnect the flow's WhatsApp number; retry later.
opted_out409NoThe customer opted out of messages from this business.Do not retry: the customer asked not to be messaged.
payload_too_large413NoThe body is over 64 KB.Send only what the flow reads.
unsupported_media_type415NoThe body was not sent as application/json.Send Content-Type: application/json.
invalid_phone422NoNo phone number at the flow's phone path, or one that cannot be read. Send it in E.164, such as +9665XXXXXXXX.Send the number with its country code, such as +966501234567.
rate_limited429YesMore than 60 requests a minute to this hook, or 1000 an hour to the account's hooks together.Retry with backoff.
template_limit_reached429YesToday's automated templates for the account are used up.Retry later, when the day's allowance frees up, or drop the event.
customer_limit_reached429YesThis customer has had 3 automated templates in the last 24 hours.Retry later, or drop the event.
service_unavailable503YesHooks are paused on our side, or we could not count requests. Try again in a minute.Retry after a minute, with the same Idempotency-Key.

status may gain values. Treat one you do not know as a failure you did not expect: log it with its detail, and use the HTTP status to decide whether to retry.

Retry or not

  • Retry later, with the same Idempotency-Key: rate_limited, template_limit_reached, customer_limit_reached, channel_unavailable, service_unavailable, any 5xx, and a timeout or a connection that failed. Back off exponentially, starting at about a minute.
  • Do not retry unchanged: every other status. The same request fails the same way until you change the request, the flow or its settings.
  • Never retry opted_out: the customer asked not to be messaged.
  • accepted and duplicate are both success. A duplicate means an earlier request with the same key already started the run whose id you receive.

Order of checks

A request is checked in this order, and the first failure is the answer:

  1. the per-address limit (429, plain text);
  2. Content-Type (415) and size (413);
  3. whether flow triggers are paused on our side (503);
  4. that the URL's token exists (404);
  5. the per-URL and per-account rate limits (429, 503 if we cannot count);
  6. the Idempotency-Key length and that the body is JSON (400);
  7. the account's plan (403);
  8. that the flow is published, switched on and started by this trigger (409);
  9. the Idempotency-Key against earlier runs (200 duplicate);
  10. the flow's WhatsApp number (409 channel_unavailable);
  11. the customer's phone number (422);
  12. the account's and the customer's template limits (403, 429);
  13. whether the customer opted out (409 opted_out).

A request refused at any step starts nothing, and its Idempotency-Key stays unused.

After 202 accepted

The run is queued, not finished. It can still end without sending anything, for example when someone on your team is already handling the conversation. Subscribe an endpoint to flow.completed and flow.failed to learn how a run ended; both carry the run id you received. A run that is skipped or cancelled before it ends sends neither event.

On this page