Concepts
Rate limits
Limits keep the platform fast for everyone and protect your workspace from a runaway script ringing hundreds of people. Every limit answers 429 with a clear code.
The limits
| Limit | Default | Error code |
|---|---|---|
| Requests per workspace | A rolling per-minute budget shared by all your keys | rate_limited |
| Outbound calls per minute | 10 per workspace | call_rate_limited |
| Outbound calls per day | 500 per workspace | call_daily_limit |
| Plan quota | The calls included in your plan | quota_exceeded |
All of them answer 429 with type: rate_limit_error.
Request rate
Requests are counted per workspace, across all of its keys. When the budget is spent the API answers 429 with a Retry-After header: the number of seconds to wait. Normal integrations — syncing calls into a CRM, starting campaigns — stay far below it.
Outbound calls
POST /calls has its own, tighter limits, because each request rings a real phone: by default 10 calls a minute and 500 a day per workspace. Space out large batches instead of sending them at once.
Need more?
The defaults suit most workspaces. If you run larger campaigns, contact us at kontakt@voximate.no and we will raise them.
Plan quota
When your plan’s calls are used up, starting a call answers 429 quota_exceeded. Reading data keeps working. Upgrade the plan in the dashboard under Billing.
Backing off
- Honour
Retry-Afterwhen it is present. - Otherwise wait 0.5 s, then 1 s, 2 s, 4 s … with a little random jitter, and give up after a few attempts.
- Send an
Idempotency-Keyon everyPOSTyou might retry.
voximate.js
// Retry 429 and 5xx with exponential backoff; never retry other 4xx.
async function voximate(path, init = {}, attempt = 0) {
const res = await fetch(`https://api.voximate.no/public/v1${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.VOXIMATE_API_KEY}`,
'Content-Type': 'application/json',
...init.headers,
},
});
const retryable = res.status === 429 || res.status >= 500;
if (retryable && attempt < 4) {
const retryAfter = Number(res.headers.get('Retry-After'));
const wait = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(30_000, 500 * 2 ** attempt) + Math.random() * 250;
await new Promise((r) => setTimeout(r, wait));
return voximate(path, init, attempt + 1);
}
const body = await res.json();
if (!res.ok) {
const err = new Error(body.error.message);
Object.assign(err, { type: body.error.type, code: body.error.code, requestId: body.request_id });
throw err;
}
return body;
}