Developers
API & MCP documentation
A REST API for your workspace, and a hosted MCP server so an AI assistant can read your metrics and run your chatbots directly.
Base URL
https://api.matram.aiREST endpoints sit under /api/v1/. The MCP server is the one exception at /mcp, with no /api prefix, because MCP clients expect a bare path.
The API and the MCP server are available on the Standard and Pro plans. On Basic every request returns 403 FORBIDDEN, even with a valid key.
Quick start
Create a key in Profile & Team → API keys. The key is shown once and only a hash is stored, so copy it before closing the panel. Choose read only unless you need to create things — it is the right choice for connecting an assistant, because it cannot spend your message quota.
curl https://api.matram.ai/api/v1/analytics?days=30 \
-H "Authorization: Bearer hk_live_your_key_here"{
"window_days": 30,
"since": "2026-08-29T09:00:00.000Z",
"conversations": 183,
"leads": 19,
"chatbots": 2,
"escalations": 4,
"resolved_without_human_pct": 98,
"usage": { "messages_used": 771, "messages_quota": 5000, "messages_remaining": 4229, "unlimited": false },
"top_questions": [ { "question": "what is the price", "count": 22 } ],
"channel_breakdown": [ { "name": "widget", "count": 171 }, { "name": "whatsapp", "count": 12 } ],
"notes": "top_questions is computed from at most the 500 most recent visitor messages, … Every other figure is exact."
}Read the notes field. Some figures are computed from a capped sample and it says which — report those as a ranking, not an exhaustive count.
Authentication
Every request carries a bearer key. Keys are workspace-scoped: a key can only ever see and change the workspace it was created in.
Authorization: Bearer hk_live_...Scopes
A key is either read or read,write, chosen at creation and fixed afterwards. To widen access, create a new key and revoke the old one — a leaked read-only key can never be quietly upgraded.
readAnalytics, chatbots, conversations and leads.read,writeThe above, plus creating chatbots, adding sources, and chatting. Chat counts as a write because it stores messages and spends your monthly quota.REST endpoints
/api/v1/analyticsreadConversations, leads, escalations, resolution rate, quota usage, top questions, channel breakdown. Accepts days (1–365, default 30; larger values are capped at 365) and chatbotId./api/v1/chatbotsreadEvery chatbot in the workspace with its id and status./api/v1/chatbotswriteCreate a chatbot. It starts in draft and cannot answer until it has a source./api/v1/chatbots/{id}/sourceswriteAdd a training source and queue ingestion. Returns once queued, not once trained./api/v1/chatbots/{id}/chatwriteSend a message and stream the answer back as server-sent events./api/v1/conversationsreadConversation metadata. Transcripts are not exposed. Accepts limit (1–200, default 50) and chatbotId./api/v1/leadsreadLeads captured in conversation, with the assistant's summary of each chat. Accepts limit (1–200, default 50) and chatbotId.Chat streams, it does not return JSON
POST /api/v1/chatbots/{id}/chat replies with server-sent events. Each line is data: <json>, one of three shapes: token carries a fragment of the answer, done carries the conversation id and any citations, and error reports a failure. An error frame can arrive after tokens, so keep reading until the stream closes rather than assuming the first tokens mean success.
curl -N https://api.matram.ai/api/v1/chatbots/YOUR_BOT_ID/chat \
-H "Authorization: Bearer hk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"visitorId":"demo-1","message":"What are your opening hours?"}'
data: {"type":"token","content":"We are open "}
data: {"type":"token","content":"9am to 6pm."}
data: {"type":"done","conversationId":"…","messageId":"…","sources":[]}Once the key is accepted, chat always answers HTTP 200 with text/event-stream. Only a key problem (401, 403 or 429) comes back as a normal JSON error. Everything else arrives as an error frame with the same code values as the rest of the API:
data: {"type":"error","code":"BOT_NOT_READY","message":"This assistant is still training. Try again soon."}BAD_REQUEST: the body is not valid JSON or did not validate, or the chatbot is not in your workspace (the message isUnknown bot).BOT_NOT_READY: the chatbot is in draft, still training, or its training failed.LIMIT_REACHED: the monthly message quota is used up. (A workspace whose trial or subscription has lapsed gets no error frame: the bot sends a short “assistant is unavailable right now” reply instead.)UNAVAILABLE: an upstream model or embedding provider failed. Retry.INTERNAL: our bug. Details are logged on our side.
Training a new chatbot
A chatbot created through the API starts in draft and cannot answer anything. Add a source, then poll GET /api/v1/chatbots until its status is ready. Ingestion runs in the background and can take minutes on a large site.
curl -X POST https://api.matram.ai/api/v1/chatbots/YOUR_BOT_ID/sources \
-H "Authorization: Bearer hk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"type":"website","config":{"url":"https://example.com"}}'Connect an AI assistant
Matram runs a hosted Model Context Protocol server at https://api.matram.ai/mcp. It speaks Streamable HTTP and is stateless — no session to keep alive. Point a client at it with your API key and the assistant can answer questions about your workspace directly.
Claude Code
claude mcp add --transport http matram https://api.matram.ai/mcp \
--header "Authorization: Bearer hk_live_your_key_here"Claude API
"mcp_servers": [
{
"type": "url",
"url": "https://api.matram.ai/mcp",
"name": "matram",
"authorization_token": "hk_live_your_key_here"
}
]What the assistant can do
A read-only key exposes four tools — analytics, chatbots, leads and conversations. A read-write key adds three more: creating a chatbot, adding a training source, and asking a bot a question. A read-only key is never told the write tools exist, so an assistant cannot try one and be refused.
Which clients work today
Clients that sign in instead of using a key
claude.ai, ChatGPT and Gemini Enterprise refuse custom API keys and require OAuth, so Matram runs an OAuth 2.1 authorization server for them. There is nothing to configure and no key to paste: add https://api.matram.ai/mcp as a custom connector, and the client discovers the rest.
You will be sent to Matram to sign in and choose which workspace to grant, then straight back. The default is read-only. You can revoke the connection at any time from Profile & Team.
Use api.matram.ai/mcp rather than matram.ai/mcp for these clients. OAuth discovery requires the address to match exactly, and the shorter one is an alias that cannot advertise itself. Both work for API-key clients.
Consumer Gemini is the one exception, and not something we can fix: Google does not support custom MCP connectors on gemini.google.com at all.
Errors and limits
Failures return a flat JSON body with two fields: a stable code you can branch on, and a message. Match the code, not the message — messages are written for humans and change.
{ "code": "FORBIDDEN", "message": "The public API requires the Standard plan or higher" }BAD_REQUESTMalformed JSON, a body or parameter that did not validate, or a chatbot id that is not in your workspace.UNAUTHORIZEDMissing, malformed or revoked key.LIMIT_REACHEDCreating a chatbot or a training source would go past your plan's cap.FORBIDDENYour plan has no API access, or a read-only key tried to write.RATE_LIMITEDMore than 120 requests in a minute on one key.INTERNALSomething failed on our side, a database read included — you get this rather than zeros or an empty list. Details are logged, not returned.There is no 404
No v1 endpoint answers 404 for a chatbot. An id that does not exist, is not a valid id, or belongs to another workspace gets 400 BAD_REQUEST with the message Unknown chatbot — on adding a source, on analytics, and on the chatbotId filter of conversations and leads. A filter never quietly returns zeros for a chatbot you do not have. Chat reports the same case inside its stream, as described above.
Bad input
These all return 400 BAD_REQUEST. An omitted or empty limit means 50, and an omitted or empty days means 30. Values above the maximum are capped rather than refused.
Body is not JSON, or empty → "Invalid JSON body" (POST chatbots, POST sources)
limit is 0, negative, 2.5, "x" → "limit must be a whole number from 1 to 200"
days is 0, negative, 2.5, "x" → "days must be a whole number from 1 to 365"MCP errors
The MCP endpoint speaks JSON-RPC, so its failures take the JSON-RPC shape rather than the flat one above:
{ "jsonrpc": "2.0", "id": null, "error": { "code": -32600, "message": "Invalid or revoked API key" } }-32600The key was refused: missing, revoked, or a plan without API access. A 401 carries the WWW-Authenticate header that starts OAuth. 429 when rate-limited.-32700The body is not valid JSON.-32600Valid JSON that is not a request: null, a string, a number, a batch array, or no method.-32601Unknown tool, or one this key's scope cannot use — deliberately not told apart.A tool that runs and fails is not a protocol error. It comes back as a normal result with isError: true and the reason in the text, so the assistant can read it and correct itself. The tools apply the same rules as REST to limit, days and chatbot_id:
{ "jsonrpc": "2.0", "id": 3, "result": {
"content": [ { "type": "text", "text": "matram_list_leads failed: No chatbot 'abc' in this workspace." } ],
"isError": true } }Rate limit
120 requests per minute per key, as a sliding window. Exceeding it returns 429 RATE_LIMITED. The limit is per key, so separate keys for separate integrations keep one busy job from starving another.