API overview
Mevichat exposes a REST HTTP API for the embedded widget and server-to-server scripts. Everything else — bots, knowledge sources, API keys, workspace settings, billing — is managed in the Mevichat dashboard.
| Endpoint | Who calls it | Why |
|---|---|---|
POST /api/chat/ | The embedded widget on your site | Simple request/response with Server-Sent Events (SSE) for streaming tokens. |
GET /api/widget/config/ | The widget at boot | Returns theme + behavior config for a public key. |
GET /api/conversations/:id/export.json | Your own scripts | Pull a full transcript for archival or analysis. |
Authentication
| Caller | Endpoint | Auth | How |
|---|---|---|---|
| Widget | POST /api/chat/ | Public API key + Origin whitelist | Send public_key in the JSON body. The server checks the request Origin header against the key's allowed domains. |
| Widget boot | GET /api/widget/config/?public_key=... | Public API key + Origin | No JWT — same domain whitelist as /api/chat/. |
| Owner / operator | POST /api/chat/playground/ | JWT (Meviona SSO) | Authorization: Bearer <token>. Session ownership is scoped to your workspace. |
| Owner / operator | GET /api/conversations/:id/export.json | JWT + workspace membership | Same Bearer token; the session must belong to your workspace. |
Public API keys carry the prefix mvc_pk_ and ship in client-side HTML. The security boundary is the key's allowed domains list, not its secrecy. See Bot API keys for creation and rotation.
JWTs are issued by Meviona SSO (Google OAuth2). They carry a workspace claim — you cannot read another workspace's data even with a valid token.
Rate limits
Enforced per endpoint:
| Endpoint | Limit | Key |
|---|---|---|
POST /api/chat/ | 60 requests/minute | Client IP |
POST /api/chat/playground/ | 120 requests/minute | User ID |
GET /api/conversations/:id/export.json | 30 requests/minute | User ID (authenticated) or IP |
Monthly message quota
Independent of request-rate limits. Each assistant reply (successful stream) counts against the workspace's monthly message cap:
| Plan | Messages / month |
|---|---|
| Free | 100 |
| Pro | 5,000 |
| Scale | 25,000 |
Quotas reset on the first of each month. When a workspace hits its cap, /api/chat/ returns an SSE error event with code: "quota_exceeded" and no LLM call is made. Failed streams (LLM errors, moderation blocks) do not consume quota.
See Billing & plans for the full limits table.
Versioning
There is no version prefix in the URL and no X-API-Version header today. The API is in active development — we version by changelog. Breaking changes are announced on the Changelog page at least two weeks before they land, with a dual-write window when feasible.
If you need long-term stability guarantees for a specific field or endpoint before we reach v1, reach out — we'll work out a compatibility plan with you.
Error format
REST (non-SSE)
All JSON endpoints return a structured error body:
{ "error": "invalid_api_key" }
The HTTP status code matches the condition:
| Status | Example codes |
|---|---|
| 400 | invalid_json, invalid_message, message_too_long, invalid_session_id |
| 401 | invalid_api_key, not_authenticated, authentication_required |
| 403 | origin_not_allowed, forbidden, no_workspace |
| 404 | session_not_found, bot_not_found |
| 405 | method_not_allowed |
| 429 | rate_limited |
The export endpoint uses detail instead of error (e.g. {"detail": "authentication_required"}) to match Django REST conventions. All other REST endpoints use error.
SSE stream (/api/chat/)
Errors mid-stream are delivered as events, not HTTP status codes — the stream is already open. Watch for an error event followed by done:
event: error
data: {"code":"quota_exceeded","plan":"free","used":100,"cap":100,"message":"..."}
event: done
data: {"finish_reason":"quota_exceeded"}
Next steps
- REST API reference — every endpoint with request, response, and streaming event format.