Rate limits

Limits are per API key, so one key's burst cannot starve another.

These count REQUESTS, not messages. One request carries up to 10,000 recipients, so the live send limit of 60 requests a minute is 600,000 SMS a minute — not 60. Nothing caps how many messages you may send; that is bounded only by the credits you have bought.
EndpointTest keyLive keyMessages/min (live)
POST /api/v1/sms/send10 req/min60 req/min600,000
POST /api/v1/otp/send10 req/min30 req/min30 — one code per request
POST /api/v1/otp/verify60 req/min—
POST /api/v1/voice/send5 req/min20 req/min200,000 calls
Everything else100 req/min—

If you are sending 100 SMS a second — 6,000 a minute — that is one request per minute with all 6,000 recipients in it. You would be using about a sixtieth of the allowance.

OTP sending is limited harder than ordinary sending on purpose. It will deliver an SMS to any number a caller names, so a stolen key must not be able to drain your balance — or bombard someone's handset — at full speed.

Voice sending is limited hardest of all, for the same reason plus one more: an unwanted text is deleted, while an unwanted call interrupts someone, possibly at night. One request takes up to 10,000 recipients, so the low limit costs a legitimate integration nothing.

Sending in bulk

Do not loop. One request takes up to 10,000 recipients and is both faster and cheaper in round trips than 10,000 requests. This is also why the limits above are never the constraint in practice — the only integrations that hit them are the ones sending one message per request.

Node.js
// Don't do this — one request per recipient, rate limited immediately.
for (const phone of numbers) {
  await sendSms(phone, message);
}

// Do this — one request, up to 10,000 recipients.
await fetch("https://api.jkasms.com/api/v1/sms/send", {
  method: "POST",
  headers,
  body: JSON.stringify({ sender: "JKASMS", message, recipients: numbers }),
});

For more than 10,000, chunk into batches of 10,000 and give each its own idempotency key.

Why there is a limit at all

Not to ration what you have bought — your credits are yours, and how fast you spend them is your business. The limit exists for the key itself: a secret that leaks into a public repository or a client-side bundle can otherwise empty an entire bundle in seconds, before anyone sees an alert. A ceiling turns that into minutes, which is the difference between revoking a key and replacing a bundle.

You can also cap a key yourself. Set a monthly message limit on any key from the dashboard, which is the right tool for “this integration should never send more than 5,000 a month”.

When you are limited

JSON
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Retry in 37s."
  }
}

Returned with 429. Back off for the stated time — retrying immediately just consumes the next window.