Public API
Rate limiting & idempotency
A per-key fixed-window rate limit protects shared infrastructure; Idempotency-Key lets your safe retries skip the side effects you already paid for.
Per-key rate limit
Requests are counted per API key on a 1-second sliding bucket. The default ceiling is 80 requests per second; raise or lower it per key in Integrations → API Keys → Advanced. The limit applies across all endpoints — sending messages, listing templates, syncing contacts all consume from the same bucket.
When you exceed the limit:
- HTTP
429with Meta errorcode: 4 - Response header
Retry-Afterwith the number of seconds to wait before the next attempt - No partial side effects — the request is rejected before reaching the business logic
Admin keys get a second bucket
For sflo_admin_ keys the configured limit is still the ceiling for the whole key, but a second counter caps any single organization at half of it. One organization running a bulk job therefore cannot starve its siblings on the same key.
With the default 80/s, an admin key can push 80 req/s in total but at most 40 req/s into any one organization. Exceeding the per-organization share returns 429 even though the key as a whole still has headroom—the error message names which ceiling you hit. Organization keys (sflo_live_) are unaffected: one organization means the two counters are equivalent.
Idempotency-Key
Mutation endpoints (POST, PATCH, PUT) accept an Idempotency-Key request header. SigFollow caches the response for 24 hours on the tuple (api_key.id, organization, idempotency_key). Subsequent identical requests replay the original response without re-executing the handler.
The organization is part of the key, which matters for admin keys: reusing one Idempotency-Keyacross two organizations (common when the key is derived from your own order ID) executes in both, rather than replaying the first organization's response into the second.
Send a key that is reasonably unique—UUIDv4 works well:
POST /v1/PHONE_NUMBER_ID/messages HTTP/1.1
Host: api.sigfollow.com
Authorization: Bearer sflo_live_xxx
Idempotency-Key: 8c7f0c50-3d8b-4d9e-9b1a-1cb2dc1ba2b4
Content-Type: application/json
{ "messaging_product": "whatsapp", "to": "...", "type": "text", "text": { "body": "Hi" } }The replay carries an additional response header so you can detect it:
HTTP/1.1 200 OK
Idempotency-Replayed: true
Content-Type: application/jsonRules and caveats
- Only successful responses (
2xx) are cached. Failed responses are not cached because the failure may be transient or parameter-related; you should retry without changing the key. - Keys are scoped per
api_key.id. Two different keys with the same idempotency value do not collide. - Keys are not scoped per endpoint path. Reusing the same key across different endpoints will replay an earlier response—use a fresh key per logical operation.
- During in-flight execution, the server holds a 60-second lock on
(api_key.id, idemKey)to prevent double execution. A second request landing while the first is still running is rejected immediately with409 Conflict, body{ "error": "idempotency_in_flight", ... }, and the response headerRetry-After: 1. The caller must back off and retry — the second request does notblock and wait for the winner's response.
GET) the header is ignored—reads are naturally idempotent.Backoff strategy
Recommended retry plan for 429 and 5xx:
attempt 1 → wait 1s
attempt 2 → wait 2s
attempt 3 → wait 4s
attempt 4 → wait 8s
attempt 5+ → wait 16s (cap)
honor Retry-After when presentAlways include the same Idempotency-Key across retries, otherwise a partially-applied call (e.g. message accepted but client timed out) will produce duplicate outbound messages.