# MJX CRM API rate limits, errors and CORS

> The response envelope, every HTTP status the MJX CRM API returns, the 120-a-minute key limit, size limits, CORS rules and how to retry safely.

Source: https://pathshala.mjxtechnologies.com/docs/developers/rate-limits-and-errors/

Every MJX CRM API answer uses one JSON envelope, and every error carries a plain sentence you can show or log. This page lists the statuses, the limits and the CORS rules.

## The envelope

```json
{ "success": true,  "data": { … } }
{ "success": false, "error": { "message": "That API key is not valid, or it was revoked." } }
```

Some site-wide errors (such as the general rate limit) add a `code`, for example `"code": "RATE_LIMITED"`. Do not rely on the exact wording of messages — use the HTTP status in code, and show the message to people.

The MCP server uses JSON-RPC 2.0 errors instead; see [MCP server](developers/mcp-server).

## HTTP statuses

| Status | Meaning | What to do |
|---|---|---|
| 200 | OK (also: a lead that already existed, with `"duplicate": true`) | — |
| 201 | A lead or note was created | — |
| 400 | Something in your request is wrong — a bad `status`, a bad date, no phone or email, no `note` | Fix the request; the message says what |
| 401 | No key, or the key is wrong or revoked | Check the header; make a new key if it was revoked |
| 402 | Lead sources only: this kind of source needs MJX CRM Pro | Move to Pro, or use a website source |
| 403 | CRM not on, not on Pro, read-only key used to write, or (Google Ads) a wrong key | Read the message |
| 404 | No such lead, endpoint or lead source | Check the id or address |
| 410 | Lead sources only: the source is switched off | Switch it on in Integrations |
| 422 | Lead sources only: the lead could not be made | Read the message; it is also shown as "Last problem" on the source |
| 429 | Too many requests | Wait and retry with back-off |
| 500 | "Something went wrong on our side. Try again." | Retry later; contact support if it continues |
| 503 | "Could not check that key just now. Try again." | Retry after a few seconds |

## Rate limits

| Limit | Value | Applies to |
|---|---|---|
| Per API key | 120 requests a minute | `/api/v1/crm/*` and `/mcp` together |
| Per internet address | A general site-wide limit (by default 100 requests a minute) | Every request to the site |

The per-key limit counts by key, not by address, so several servers sharing one key share one budget. Answers carry the standard `RateLimit-*` headers so you can see how much is left. When you go over:

```json
{ "success": false, "error": { "message": "Too many requests for this key — at most 120 a minute. Slow down and try again." } }
```

> [!TIP]
> For a sync job, use `updated_since` and `limit=100` instead of fetching every lead one by one. For new leads, use a [webhook](developers/lead-webhook) instead of polling.

## Other limits

| Item | Limit |
|---|---|
| `limit` on `GET /leads` | 1–100 (default 50) |
| `limit` on MCP `search_leads` | 1–50 (default 20) |
| `q` search text | 80 characters |
| `message` on a lead | 5,000 characters |
| Extra details kept per lead | 30 fields, 500 characters each |
| Note | 2,000 characters including the key's name (MCP: 1,900 for the note) |
| Tags per lead (MCP) | 10 |
| API keys per institute | 20 at a time |
| Webhooks per institute | 10 |
| Lead sources per institute | 20 |
| Lead source body | 256 KB; FormData 80 fields of 20 KB, files dropped |
| Webhook answer time | 5 seconds |

## CORS

| Path | Browser calls from other sites |
|---|---|
| `/api/v1/crm/*` | Allowed from any origin, **without cookies**. Methods `GET, POST, PATCH, OPTIONS`; headers `Content-Type, Authorization, X-Api-Key, Accept` |
| `/hooks/lead/*`, `/hooks/call/*` | Allowed from any origin, without cookies — this is how a website form posts straight to a lead source |
| `/mcp` | Meant for servers and desktop AI clients, not browsers |

> [!WARNING]
> CORS being open does not make it safe to put an API key in a web page. Anyone can read a page's code. Use a lead source address (no key) for browser forms.

## Retrying safely

- **POST /leads** — safe to retry: a known phone or email returns the existing lead.
- **PATCH /leads/{id}** — safe to retry: it sets values, it does not add to them.
- **POST /leads/{id}/notes** — not safe to retry blindly: each call adds a note.
- **Webhooks to you** — we retry once after a minute with the same `X-MJX-Delivery`; ignore a delivery id you have already handled.

## Versioning

The version is in the path (`/api/v1/crm`). New fields and endpoints can appear in v1 at any time; ignore fields you do not know. Removing or renaming a field would come with a new version path.

## Questions people ask

### What is the API rate limit?

120 requests a minute per API key, shared by the REST API and the MCP server. A general limit per internet address also protects the whole site.

### Can I call the API from a browser?

CORS is open for /api/v1/crm, but a key in a web page can be copied by anyone. Call the API from a server, and use a lead source address for browser forms.

### Is it safe to retry a POST /leads?

Yes. A lead with the same phone (or email) is not added twice; the retry returns the existing lead with duplicate true.
