API reference
Errors and status codes.
Every status the API returns, what usually causes it and whether it’s safe to retry. Error responses carry a JSON body with an error message you can show or log.
Status codes
202Accepted- A live send was queued and its quote reserved.
Store the message ID and wait for webhooks or check the status.
Retry: No200OK- A quote or read succeeded.
- A send was replayed with the same Idempotency-Key and payload: nothing new was sent.
- A sandbox simulation returned delivered.
Use the returned ID. For a replay, it’s the original message.
Retry: No400Bad request- The body isn’t valid JSON.
- A field is missing or invalid, for example a body over 3,000 characters or an email subject over 200.
- consent: true is missing.
Read the error message, fix the request and send it again with a new key.
Retry: After fixing401Unauthorized- The Authorization header is missing or the key is wrong or revoked.
Send Authorization: Bearer with a current key from the console.
Retry: After fixing402Insufficient funds- The available balance can’t cover the quote.
- A sandbox simulation with scenario insufficient_funds.
Top up the wallet, then retry the same request.
Retry: Yes, after a top-up403Forbidden- The channel isn’t enabled for this key or workspace.
- A sandbox key tried to make a live request.
Check the key’s channels and the workspace’s channel settings.
Retry: After fixing404Not found- The message, contact or endpoint doesn’t exist in this workspace.
Check the ID and that the key belongs to the right workspace.
Retry: No409Conflict- An Idempotency-Key was reused with a different payload.
- The quote is higher than your maxCostMicros cap.
Use a new key for a new send, or raise the cap after checking the quote.
Retry: With a new key422Can’t be processed- The channel or sender isn’t set up yet.
- The WhatsApp template isn’t approved, or its parameters don’t match.
- A sandbox simulation with scenario rejected.
Finish the channel setup or sync and fix the template.
Retry: After fixing429Too many requests- More than 60 requests in a minute from this workspace.
- The daily Smart assist limit was reached.
Wait for the Retry-After seconds (60), then retry. Batch sends where you can.
Retry: Yes, after waiting5xxServer error- Something failed on our side or a dependency was unavailable.
Retry with the same Idempotency-Key and back off. It can’t double-send.
Retry: Yes, same key
Retries
Retry safely.
Keep the same Idempotency-Key on every retry of the same send. SavaraFlow returns the original message instead of sending twice.
send-with-retries.jsNode.js1async function send(payload, key) {
2 for (let attempt = 0; attempt < 4; attempt++) {
3 const res = await fetch(`${process.env.SAVARA_HOST}/api/v1/messages`, {
4 method: "POST",
5 headers: {
6 Authorization: `Bearer ${process.env.SAVARA_API_KEY}`,
7 "Content-Type": "application/json",
8 "Idempotency-Key": key, // same key on every retry
9 },
10 body: JSON.stringify(payload),
11 });
12 if (res.status === 429) { await wait(60_000); continue; }
13 if (res.status >= 500) { await wait(2 ** attempt * 1000); continue; }
14 return { status: res.status, body: await res.json() };
15 }
16 throw new Error("SavaraFlow unavailable, try again later");
17}
Error bodies look like { "error": "Insufficient available wallet funds." }. Quotes and retries
Trigger each error on purpose.
Sandbox scenarios return 200, 422 and 402 without contacting a provider.