Rate limits & idempotency
Per-key rate limits, safe retries with Idempotency-Key.
Rate limits
Every sk_live_* key has a per-minute rate budget. If you exceed it, the
API returns 429 Too Many Requests with headers describing the window:
HTTP/2 429 Too Many Requests
Retry-After: 17
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1776791400Retry-After— seconds until the next slot opens.X-RateLimit-Limit— the window's maximum.X-RateLimit-Remaining— tokens left in the current window.X-RateLimit-Reset— Unix timestamp when the window rolls.
Limits scale with tier. Contact us if you need a custom ceiling for a launch or a batch import.
Idempotency
POST /v1/calls and POST /v1/calls/batch accept an Idempotency-Key
header. A repeated request with the same key and the same body within
24h returns the original response instead of creating a duplicate call.
When to use it
- Retries on 5xx / network errors. Send the same
Idempotency-Keyon every retry. Either the first attempt succeeded (you get the original response), or it didn't (a new call is created on the retry). - Webhook fan-outs that trigger calls. Derive the key from your own upstream event id so a duplicate webhook fires the call exactly once.
What "same body" means
If you reuse a key but change any field in the body, the request fails
with 409 Conflict. Idempotency keys are per-payload, not per-intent.
Key format
- 1–255 characters of
[A-Za-z0-9_.:-]. - Must be globally unique to your tenant for the 24h window.
- UUIDv4 works fine. So does
"shopify_order_{id}"if you're deriving from an upstream event.
Example
curl -X POST https://api.openphn.com/v1/calls \
-H "Authorization: Bearer $OPENPHN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: shopify_order_4221" \
-d '{ "to": "+14155551234", "objective": "...", ... }'If the first request times out, retry with the same header. Either the
call was created (you get the same call_id) or a new one is created now.
No duplicates.