# 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.

Source: https://docs.amomic.in/operate/limits

---

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](/operate/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](/operate/credits) | Paid from [credits](/operate/credits) | Per contract |
| Channels | Web chat | Web chat, WhatsApp, and voice paid from credits | Everything, including voice | Everything |
| [Campaigns](/campaigns/overview) | — | — | 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](/operate/credits#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](/console/billing#plans). [Upgrades, downgrades & trials](/operate/plan-changes) 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.

::: note 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](/console/billing#usage-this-cycle). 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](/operate/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](/operate/credits#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](/operate/plan-changes#when-a-payment-fails).

::: warning 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](/operate/plan-changes#moving-to-free-or-cancelling).
:::

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](/api/errors) lists every reason.

## Campaign recipients

A [campaign](/campaigns/overview) 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`.

::: note 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](/campaigns/sending-rules#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: 120
X-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

```json title="429 Too Many Requests"
{
  "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:

```python
import time
time.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](/api/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.

```json title="429 Too Many Requests"
{
  "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 |

::: note 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](/api/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](/recipes/sync-conversations) is the job for that.

## Related

::: cards

::: card Rate limits in depth
[The window, the headers, and pacing](/api/rate-limits) — including what a backfill costs.
:::

::: card Going live
[The pre-launch checklist](/operate/going-live) — including how to work out your rate-limit headroom.
:::

::: card Troubleshooting
[Symptom-first index](/operate/troubleshooting) — including both flavours of `429`.
:::

::: card Errors
[Every code and reason](/api/errors) in one place.
:::

:::
