Authentication
The Mojeeb Public API uses API keys, not JWTs. Each key is a long-lived server-to-server credential issued from the dashboard and scoped to your organization. Send the key as a Bearer token over HTTPS.
How do I send my API key?
Pass the key in the standard Authorization header:
Authorization: Bearer mk_live_8aB3cDe4FgH5iJ6kLm7nOp_a1b2c3d4e5
HTTPS only. Plain HTTP requests are rejected by the load balancer before they reach the API.
What does the key format look like?
mk_live_<22 chars>_<10 char checksum>
Example: mk_live_8aB3cDe4FgH5iJ6kLm7nOp_a1b2c3d4e5
mk_— Mojeeb prefix; grep-able in logslive_— environment marker (test_is reserved for a future sandbox)- 22-character body with 130 bits of entropy
- 10-character checksum so the API can reject malformed keys before any database lookup
The checksum protects you against typos: a one-character mistake fails locally, fast.
Where do I get a key?
- Sign in to the Mojeeb dashboard. Your organization needs the Starter or Professional plan. You must be the owner, or an admin with access to every agent.
- Open the API Keys page from the sidebar
- Click Create key, give it a name, and confirm
- Copy the secret immediately — it's shown once and never again
If you lose a key, revoke it from the dashboard and create a new one. There is no way to recover the original secret.
The same keys work with the Mojeeb MCP server, which lets AI assistants such as Claude or Cursor call this API. Give each assistant a key of its own, limited to the agents it needs.
What are scopes?
Scopes name what a key may do, in resource:action format. Today every key is issued with full access, the * scope: it can call every endpoint the API offers, on every agent in its organization.
| Scope | Allows |
|---|---|
* | Every current and future endpoint. What every key holds today. |
whatsapp:send | Send WhatsApp text messages and templates, and read a sent message's status (GET /v1/whatsapp/messages/{id}). Keys issued before October 11, 2026 held only this scope; they now hold *. |
Every page of the API reference already shows the scope its endpoint will require (x-scope), so a key can later be limited to reading, or to one kind of data:
| Scope | Endpoints |
|---|---|
whatsapp:read | A WhatsApp number's templates |
contacts:read / contacts:write | Contacts |
notes:read / notes:write | A contact's notes |
leads:read / leads:write | Leads, including assigning, pinning and deleting them; the agent's lead fields; and the AI's lead capture prompt |
knowledge:read / knowledge:write | Knowledge bases |
connections:read / connections:write | Connections and their AI switches; connections:read also reads the website widget and its embed code |
agents:read / agents:write | Agents (listing and reading them) and their settings: name, description, Main Instructions, time zone, AI handoff, comment auto-hide and follow-ups |
team:read | Your team: members, their roles and emails, and the agents each can open |
usage:read | Your plan, and its message and agent usage now and per billing period |
analytics:read | An agent's daily analytics |
custom_api:read / custom_api:write | An agent's custom API tools and their runs; custom_api:write also tests them and changes their sites' logins |
conversations:read / conversations:write | An agent's conversations and their messages; conversations:write also changes their state and assignee and replies to customers |
comments:read / comments:write | An agent's Facebook and Instagram comments with their replies and moderation; comments:write also hides and shows them |
These scopes aren't issued yet. When they are, keys holding * keep working unchanged. team:read, usage:read and analytics:read have no write scope: the API reads your team, your plan and usage, and your analytics, and never changes them. GET /v1/me needs none: any valid key can describe itself, and its reference page shows x-scope: none.
A request without the required scope returns 403 insufficient_scope with a required_scope field telling you exactly what was missing.
Can I restrict a key to specific agents?
Not from the dashboard yet. Every key you create there works on every agent in your organization, including agents added later, and the API Keys page shows it as All agents. A key that does carry an agent list can act only on those agents: a request for another agent of your organization returns 403 agent_not_authorized, and another organization's agent returns 404 agent_not_found. On the WhatsApp send endpoints, which take agent_id in the body, any agent outside the key's list returns 403 agent_not_authorized, whichever organization it belongs to. A message's status follows the list too: GET /v1/whatsapp/messages/{id} for a message sent through an agent outside it returns 404 message_not_found, the same as an unknown id.
GET /v1/me shows a key's agent list as agent_ids (null means every agent), and GET /v1/agents lists the agents it can act on now. See Your Key and Agents.
Until the dashboard offers the choice, use one key per integration, so you can revoke one without affecting the others.
A key with an agent list is also held to it for what agents share. A knowledge base can serve several agents, so such a key can change it only when it can act on every agent that uses it (403 shared_with_other_agents otherwise). The same goes for a custom API tool's site login, which the tools of several agents can use: such a key can add a tool to it, or change it, only when it can act on every agent whose tools use it (403 shared_with_other_agents otherwise).
Some reads cover your whole organization, whatever the key's agent list: your plan and usage, and your team. A key with an agent list still sees every teammate, but each teammate's agent_ids shows only the agents on the key's list.
What can a key do?
A key acts for your organization with the access of an agent admin on its agents. It reads and changes most of what an agent admin can in the dashboard, from an agent's settings to its leads, knowledge and channels, and it reads your team, your plan and your usage. It never creates or deletes agents, and it never manages your team, billing or API keys.
- Agents: list and read them, and change an agent's name, description, Main Instructions, time zone, AI handoff and comment auto-hide. Not its status, AI model, model provider, picture or language (
422 field_not_writable). - WhatsApp: send messages and templates, list a number's templates, and look up a message's status.
- Contacts and notes: read and update contacts; read and add notes, and edit or delete the ones the key's creator wrote.
- Leads: read, create, update, assign, pin and delete leads; add, change and delete the agent's custom lead fields; and change the AI's lead capture prompt.
- Knowledge: read, add, edit and delete knowledge bases.
- Conversations: list them and read their messages, reply to customers as your team, open, close or archive a conversation and mark it read or unread, switch the AI off in it or end its pause, mark it urgent or resolved, and assign it. Not search inside message history.
- Comments: read an agent's Facebook and Instagram comments with their replies and moderation, and hide or show them.
- Channels and follow-ups: list an agent's connections and switch the AI on or off on each, read and change follow-up settings, and get the website widget and its embed code.
- Custom API tools: add, change, test, switch on and off and delete an agent's custom API tools, change their sites' logins, and read their runs (paid plans).
- Reports: read an agent's daily analytics, and your organization's plan and usage.
- Team: list your teammates with their names, roles and emails, and who can open each agent.
Deleting a lead is permanent, with no undo. A key never deletes contacts or conversations, never connects or disconnects channels, and never changes the website widget or your WhatsApp templates.
Where Mojeeb records a person, such as a note's author, who changed a lead's status or who assigned a lead, it records the person who created the key. Unlike a teammate's edit, an edit through the API never assigns an unassigned lead to anyone. Only the assign endpoints do: POST /v1/agents/{agentId}/leads/{leadId}/assign, and POST /v1/agents/{agentId}/conversations/{conversationId}/assign, which assigns the conversation's lead with it. A reply through the API never assigns the conversation either.
What happens when authentication fails?
Every authentication failure returns HTTP 401 with the standard error envelope. A single code (invalid_api_key) covers every sub-case — the message field disambiguates for humans. One exception: when Mojeeb couldn't check the key at all, the 401 carries type: internal_error and code: internal_server_error; retry with backoff and don't rotate the key.
| Sub-case | message |
|---|---|
Missing Authorization header | Missing Authorization header. Send 'Authorization: Bearer mk_live_...'. |
| Wrong scheme (e.g. Basic) | Authorization header must use the Bearer scheme. |
| Malformed, unknown, revoked, or expired key | The API key is invalid, malformed, or revoked. |
Example response:
{
"error": {
"type": "authentication_error",
"code": "invalid_api_key",
"message": "The API key is invalid, malformed, or revoked.",
"correlation_id": "req_01KQER73VQBSZK5RPVZCPW221V"
}
}
Common questions
Should I rotate keys regularly?
Yes. Treat API keys like database credentials — rotate every 90 days, rotate immediately if a key may have leaked, and use separate keys for separate environments and integrations so revocation has narrow blast radius.
Can a key read my teammates' emails?
Yes. GET /v1/organization/members and GET /v1/agents/{agentId}/members return each teammate's name, role and email, never their phone number, to any key with team:read, which every key holds today. Keep keys on your servers, and revoke a key that may have leaked.
Can I use the same key from multiple servers?
Yes. The key isn't IP-bound. The rate limit (default 60 req/min) is per key, so multiple servers sharing one key share the budget. For independent rate budgets, issue separate keys.
Is there a sandbox/test environment?
Not yet. The test_ environment marker is reserved in the key format but not currently issued. Develop against a test agent in your organization in the meantime, and use idempotency keys on WhatsApp sends so retries during development don't multiply them.
What's the difference between API key auth and the dashboard's JWT?
The dashboard authenticates users via JWT issued at login. The public API authenticates servers via long-lived API keys. Internally both produce the same authorization context — the same per-agent permission checks apply — but API keys can't be used in the browser dashboard, and JWTs can't be used against /v1/ endpoints.