Plans & limits
The four plans and what each includes, which limits actually block a create, the 120-per-minute API rate limit, call concurrency, and every field and size bound in one table.
There are two kinds of limit here and confusing them wastes an afternoon. Plan limits govern how many things your workspace can own — agents, knowledge bases, deployments, team seats. API limits govern individual requests — how fast you may call, how long a field may be, how many items a page may hold.
Plan limits are enforced in the console and in the platform when you create a resource, and your plan's monthly allowances decide when new conversations and calls need credits. API limits are enforced on every request. Your plan does not change your rate limit.
Plans #
Four plans. Prices are per month and exclude GST.
| Free | Starter | Growth | Enterprise | |
|---|---|---|---|---|
| Plan id | free |
starter |
growth |
enterprise |
| Price / month | ₹0 · $0 | ₹2,999 · $39 | ₹7,999 · $99 | Custom |
| AI agents | 1 | 3 | 10 | Custom (up to 20) |
| Knowledge bases | 1 | 3 | 10 | Custom (up to 50) |
| Deployments | 3 | 9 | 40 | Custom |
| Team seats | 2 | 3 | 10 | Custom |
| AI conversations / month | 100 | 1,000 | 5,000 | Custom |
| Voice minutes / month | — | Pay-as-you-go at ₹6 · $0.07 per min | 500 included, then ₹6 · $0.07 per min | Custom |
| Phone numbers | — | ₹399 · $3.99 per number/month | 1 included, then ₹399 · $3.99/month | Custom |
| Usage beyond the allowance | Refused until the 1st | Paid from credits | Paid from credits | Per contract |
| Channels | Web chat | Web chat, WhatsApp, and voice paid from credits | Everything, including voice | Everything |
| Campaigns | — | — | Yes, up to 5,000 recipients per launch | Yes |
Money is shown as INR · USD. Your workspace bills in one of the two, fixed when it was created — see your workspace currency. Prices exclude tax.
A conversation is one customer-to-agent thread on one channel, lasting up to 20 transactions (normally 10 exchanges) or 24 hours, whichever comes first. The same person messaging you on WhatsApp on Monday and again on Wednesday is two conversations. A long thread on Monday that passes 20 transactions rolls into a second one.
Plans are monthly. An unknown or unreadable plan id resolves to free.
You compare and change plans on Billing. Upgrades, downgrades & trials explains what each move does.
Locked features #
A feature your plan doesn't include shows a Plan chip beside it in the sidebar, and its page shows Upgrade to unlock. Campaigns, for example, are locked on Free and Starter. The owner gets a View plans & upgrade button; everyone else is asked to talk to the owner.
Voice is a separate meter from conversations
Voice minutes are counted on their own and are deliberately excluded from the conversation count, so a call is not billed twice. Web chat and WhatsApp conversations share one allowance. Conversations and voice minutes reset on the 1st of each UTC calendar month, whatever day your subscription renews on.
What is actually enforced #
This distinction matters more than the table above, because it tells you which limits can fail a request.
Three limits block a create. When you are at the cap, the create is refused with the message below and nothing is written:
| Limit | Enforced when | Message |
|---|---|---|
knowledge_bases |
You create a knowledge base | Your plan includes {limit} knowledge base(s). Upgrade to add more. |
deployments |
You create a deployment | Your plan includes {limit} deployment(s). Upgrade to add more. |
members |
You invite a team member | Your {Plan} plan includes {limit} team seats and they're all used (including pending invites). Upgrade your plan to add more. |
Agents are not refused at the plan cap when you create one in the console. The console stops only at the 20-agent ceiling, with Agent limit reached for this organization. Don't rely on the console to hold you to your plan's agent count: keep to the number in the table above. Archive an agent you no longer use rather than creating past it.
Seats count active members plus pending invites. An invitation that nobody has accepted still occupies a seat, which is the usual explanation for a workspace that appears to have room and does not. Cancel stale invites before you buy more seats.
Conversations and voice minutes are monthly meters. They are counted and shown on Billing. They never block a create. What happens when one runs out depends on the plan:
- Starter and Growth: usage past the allowance is paid from credits, at ₹6 · $0.07 per voice minute and ₹2 · $0.02 per conversation. If the credit balance is also at zero, new conversations and calls on that meter are refused, inbound as well as outbound, until you top up. See What happens when you run out.
- Free: the allowance is a hard cap. After 100 conversations, new web chat and WhatsApp conversations are refused until the 1st.
A conversation or call already in progress is never cut off.
An unpaid plan invoice is different from a spent meter. Once the workspace is suspended, everything that serves customers stops, including web chat conversations that are already open: no agent replies on web chat or WhatsApp, no WhatsApp message or call goes out, campaigns are held, and API keys are refused. Credits don't lift it; paying the invoice does. See When a payment fails.
Downgrading keeps what you've built, but not everything
If you drop from Growth to Starter with six knowledge bases, all six keep working. You just can't create another until you're back under the cap. The same goes for deployments and seats. Moving to Free is different: your WhatsApp number and phone numbers stop answering, and after 7 days the phone numbers are released for good. See Moving to Free.
Two more properties worth knowing:
- Enforcement fails open. If the entitlement lookup cannot be read, the create is allowed. A blip in our infrastructure will never block you from adding an agent. It also means an occasional create can slip past a cap; the next one will not.
- There are absolute backstops above the plan caps. A workspace cannot exceed 20 agents or 50 knowledge bases regardless of plan. You will meet your plan limit long before either.
On /api/v1, the same allowances apply. POST /messages is refused with allowance_exhausted and POST /calls with wallet_empty when the meter and the credits are both spent. A call on a number the plan no longer includes is refused with channel_dormant. Errors lists every reason.
Campaign recipients #
A campaign has two ceilings.
| Ceiling | Value | Behaviour |
|---|---|---|
| Absolute | 50,000 recipients per campaign | Never moves, on any plan |
| Plan | campaign_recipients on your plan |
Checked at launch |
Both are checked before anything is sent, and both block the launch rather than truncating the list. Sending to the first thousand of a five-thousand-person audience and silently dropping the rest would be worse than refusing: you would believe the campaign ran.
The refusal names your limit and your audience size, with details.reason of plan_limit or audience_too_large.
This counts eligible recipients, not rows
The check runs after opt-outs, duplicates and unusable numbers are removed — so a 52,000-row file with 3,000 opt-outs passes. The console shows both numbers.
Like every other plan check, this one fails open: if entitlements cannot be read, the launch is allowed and the absolute ceiling still applies.
Two limits on campaigns are not plan-based and cannot be raised by upgrading:
- 300 outbound calls per workspace per day. A call campaign launched after the day's 300 are used is refused; one bigger than what's left today launches with a warning that only part of it will be called today. Split large call lists across days.
- 4 campaign messages to one person per rolling week. See Frequency caps.
API rate limit #
120 requests per key, per minute
Counted in a fixed one-minute window keyed on the wall clock, not a sliding window. At the top of each minute the counter resets to zero. The counter is shared across every server that handles your traffic, so the limit is global rather than per-instance.
The limit is per key, not per workspace. Three keys give you three independent budgets, which is the cheapest way to stop a backfill starving your production sends.
Headers #
On every successful response where a key was checked:
X-RateLimit-Limit: 120X-RateLimit-Remaining: 87
Read X-RateLimit-Remaining and slow down before you are rejected. Note the asymmetry: these headers appear on success only. A 4xx or 5xx — including the 429 itself — carries no X-RateLimit-* header.
When you exceed it #
{"error": {"code": "rate_limited","message": "Rate limit of 120 requests/minute exceeded for this key.","details": { "reason": "rate_limited", "limit": 120, "window_seconds": 60 },"request_id": "req_01JQRS4T8XZ0AB1CD2EF3GH4","correlation_id": "cor_01JQRS4T8XZ0AB1CD2EF3GH4"}}
There is no Retry-After header and no X-RateLimit-Reset header. Because the window is a wall-clock minute, sleeping until the next minute boundary is the correct backoff and anything shorter is a wasted request:
import timetime.sleep(60 - (time.time() % 60) + 0.25)
If the counter store is unreachable, the limiter fails open and your request is served. You will never be rejected because our rate limiter had a bad day.
For bulk work, pace at roughly two requests per second rather than bursting and absorbing rejections. Rate limits covers pacing patterns in more depth.
Concurrent outbound calls #
10 live calls per workspace
Separate from the request limit, counted differently, and reported differently. This one counts calls that are currently ringing or in progress across the whole workspace, regardless of which key placed them.
{"error": {"code": "rate_limited","message": "This workspace already has 10 calls in progress (limit 10). Try again shortly.","details": { "reason": "call_concurrency", "limit": 10 },"request_id": "req_01JQRS4T8XZ0AB1CD2EF3GH4","correlation_id": "cor_01JQRS4T8XZ0AB1CD2EF3GH4"}}
Both limits produce 429 with code: "rate_limited", so branch on details.reason to tell them apart. rate_limited means slow down; call_concurrency means wait for a call to end. A loop that fires 200 calls will meet this on the eleventh — queue them and drain the queue as call.ended events arrive.
Field and size limits #
Every one of these is enforced at validation. Exceeding one returns 400 with code: "invalid_argument", the message Request validation failed., and details.errors naming the field.
| Field | Endpoint | Limit |
|---|---|---|
text |
POST /messages |
4096 characters |
to |
POST /messages, POST /calls |
6–20 characters, pattern ^\+?\d+$ |
sender_id |
POST /messages |
64 characters |
template.name |
POST /messages |
1–120 characters |
template.language |
POST /messages |
16 characters |
agent_id |
POST /calls |
64 characters |
from_number |
POST /calls |
20 characters |
purpose |
POST /calls |
500 characters |
ring_seconds |
POST /calls |
10–90, default 30 |
subject |
POST /tickets |
1–240 characters |
description |
POST /tickets |
1–8000 characters |
priority |
POST /tickets |
One of low, normal, high, urgent — default normal |
tags |
POST /tickets |
At most 10 items |
name |
POST /contacts |
120 characters |
email |
POST /contacts |
200 characters |
phone |
POST /contacts |
32 characters |
Idempotency-Key |
Header | Truncated to 200 characters |
Non-request limits that show up in the same conversations:
| Thing | Limit |
|---|---|
| Maximum call length | 60–3600 seconds, default 600 |
| Web chat image upload | 5 MB, on paid plans only |
| Knowledge base file upload | 15 MB per file |
Phone number formatting is stricter than it looks
^\+?\d+$ means digits with an optional leading + and nothing else. +919876543210 and 919876543210 both pass. +91 98765 43210, +91-98765-43210, and (+91) 98765 43210 are all rejected at validation. Normalise before you send. Responses always come back as + followed by digits.
There is no media or attachment upload on POST /messages — text and approved templates only. There is no batch send endpoint and no scheduling parameter.
Pagination bounds #
| Endpoint | limit range |
Default |
|---|---|---|
GET /conversations |
1–100 | 25 |
GET /conversations/{id}/messages |
1–200 | 100 |
GET /agents |
No limit parameter |
Returns everything |
A limit outside its range is a 400, not a silent clamp. GET /agents returns the same {items, next_cursor} envelope as the others but never paginates — next_cursor is always null.
next_cursor is non-null only when a page came back full. A short page ends the walk. See Pagination.
Retention #
| Thing | Kept for |
|---|---|
| API request log | 7 days |
| Webhook delivery records | 7 days |
| Idempotency records | 24 hours |
| Key roll grace window | 24 hours |
| WhatsApp session window | 24 hours |
| Webhook signature timestamp tolerance | 5 minutes |
The request log is the one you will use. The /api/v1 calls your keys made appear under Developers → Logs with time, method and path, key name, status with error code, and duration, for seven days. Request ids and correlation ids are not shown. Requests refused before the key is accepted (a 401, a suspended workspace's 403, or a rate-limit 429) do not appear.
If you need call or conversation history beyond what the console shows, pull it into your own store — Sync conversations into your warehouse is the job for that.
Related #
Rate limits in depth
The window, the headers, and pacing — including what a backfill costs.
Going live
The pre-launch checklist — including how to work out your rate-limit headroom.
Troubleshooting
Symptom-first index — including both flavours of 429.
Errors
Every code and reason in one place.