Server API (REST v1) and MCP
The reactive.chat REST interface for your backend – API keys and scopes, rate limiting, response and error format, pagination, all endpoints for projects, conversations, messages, visitors, events, rules and hooks – and the MCP server for AI tools.
The server API is meant for your backend, not for the browser: it does not allow CORS, and an API key never belongs in a web page or app.
Basics
- Base:
https://reactive.chat/v1/ - Version: in the path (
v1). Within v1, fields are added but none are removed; ignore unknown fields. - Format: JSON, UTF-8. Times as ISO 8601 in UTC (
2026-10-21T08:15:30.123Z). IDs are output as strings ("id":"123"). - Response headers:
Cache-Control: no-store, private,X-Content-Type-Options: nosniff. - A path that does not exist returns a 404 page (not JSON).
API keys
In your account under API keys (/app/api-keys, owners and admins only). You assign a name and a scope; the key (rc_live_ + 48 characters) is shown exactly once, and we only store a hash.
Scopes:
- read only –
read - read and write –
read,write - read + visitor data –
read,besucherdaten:lesen - read, write + visitor data –
read,write,besucherdaten:lesen - customer data import only –
kundendaten:schreiben(Customer data)
A key belongs to exactly one workspace; no path and no parameter selects another. It becomes invalid when you revoke it or when the person who created it is no longer an owner or admin of the workspace. There is no expiry date – rotate yourself (create a new one, switch over, revoke the old one).
Sending:
curl https://reactive.chat/v1/me -H "Authorization: Bearer rc_live_..."
The header X-Api-Key: rc_live_... is equivalent (it is only read if there is no Authorization: Bearer).
Rate limiting
- 120 requests per minute and key, fixed window aligned to the full minute. Every request counts, including a rejected one.
- Every response carries
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset(seconds until the next window, not a timestamp). - Above that: 429
rate_limitedwithRetry-After. - After 60 failed authentications per address within 15 minutes: 429 with
Retry-After: 900.
Response format
{ "data": { ... } }
Lists:
{ "data": [ ... ], "has_more": true, "next": { "before_id": "812" } }
Pagination: limit (default 25, at most 100) and a cursor – before_id for “newest first” lists, after_id for “oldest first” lists. next is only present if has_more is true. There is no total count.
Bodies of POST/PUT: only Content-Type: application/json (otherwise 415), at most 65,536 bytes (otherwise 413), a JSON object with at most 32 levels.
Error format
{ "error": { "code": "insufficient_scope", "message": "...", "required_scope": "write" } }
message is a fixed English sentence for developers. Depending on the error, param, required_scope, max, allowed, reason are added. The codes are exhaustive:
- 400
bad_request,bad_json - 401
auth_required(no key),auth_failed(invalid or revoked) - 402
plan_required - 403
insufficient_scope,workspace_inactive - 404
not_found,conversation_not_found - 405
method_not_allowed(withAllow) - 409
conversation_closed,import_disabled - 413
payload_too_large - 415
unsupported_media_type - 422
msg_too_long(withmax) - 429
rate_limited - 500
internal, 501not_implemented, 503unavailable
Endpoints
Account
- GET /v1/me – no particular scope required.
{ key: {id, name, scopes}, workspace: {id, name}, rate_limit: {requests, window_seconds} }. Good for checking a key.
Projects (read)
- GET /v1/projects –
limit,before_id. Per project:id,name,domain,site_key,status,locale,created_at,updated_at,last_used_at. - GET /v1/projects/{id}
Conversations (read)
- GET /v1/conversations – newest first. Filters
project_id,status(open,bot,waiting,assigned,closed),limit,before_id. Per conversation:id,project_id,status,channel,visitor_id,session_id,assignee_id,csat_score,handoff_reason,created_at,updated_at,closed_at. - GET /v1/conversations/{id}
Messages
- GET /v1/conversations/{id}/messages (
read) – oldest first,after_id,limit. Per message:id,conversation_id,client_ulid,direction(into the visitor,outfrom the visitor),author_type,author_id,kind,body,redacted,delivery_state,created_at; where presentcard,cards,form,form_reply,action,quick_replies,quick_reply_of. - GET /v1/messages (
read) – all messages of the workspace as a stream,conversation_idoptional,after_id,limit. For collecting without webhooks. - POST /v1/conversations/{id}/messages (
write) – write a message into a conversation:
curl -X POST https://reactive.chat/v1/conversations/815/messages \
-H "Authorization: Bearer rc_live_..." \
-H "Content-Type: application/json" \
-d '{"body":"Your return has arrived.","author_type":"agent","client_ulid":"01JAB3C4D5E6F7G8H9JKMNPQRS"}'
- body (string, required, at most 4000 characters)
- author_type (
agent|bot|system, defaultagent) – not on behalf of the visitor - client_ulid (ULID, optional) – for idempotency: the same ID again returns 200 with the existing message instead of a second one (201 the first time).
- 409
conversation_closedfor a closed conversation, 422msg_too_long. - Note: messages written this way are stored, but do not reach a widget that is currently open immediately – only on the next sync. For live replies, use the MCP tool
nachricht_senden(below).
Visitors (read)
- GET /v1/visitors – live visitor list:
project_id,online(0/1),limit. Per visitor, among others,online,consent,first_seen_at,last_active_at,visitor_id,page,pages_viewed,source(with UTM),device,country,language,returning,conversation. Additionallydisabled_project_idsfor projects in which the visitor list is switched off.
Events
- GET /v1/events (
read) –project_id,type,source(mp,rc,integration),after_id,limit. Per eventid,project_id,source,type,session_id,conversation_id,payload,created_at. - POST /v1/events (
write) – attach an event of your own from your system to a session or a conversation:
{ "project_id": "123", "type": "bestellung.storniert",
"session_id": "s_...", "conversation_id": "01JAB...",
"payload": { "nummer": "2026-0815" }, "ts": 1792503600000 }
type matching ^[a-z][a-z0-9_.:-]{0,47}$, payload at most 8192 bytes, ts in milliseconds (at most 7 days old, at most 5 minutes ahead). source is always integration. Response 201.
Rules (read)
- GET /v1/rules –
project_id. Per projectsource(customordefault) andrules. Read-only; you edit rules under Customisation.
Hooks – see Webhooks: GET /v1/hooks, POST /v1/hooks, DELETE /v1/hooks/{id}.
Customer data – see Customer data: PUT and DELETE /v1/kundendaten/{user_id}.
Example: collecting open conversations
<?php
$key = getenv('RC_API_KEY');
$url = 'https://reactive.chat/v1/conversations?status=waiting&limit=100';
do {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key]]);
$antwort = json_decode((string) curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status === 429) { sleep(60); continue; }
foreach ($antwort['data'] as $g) { echo $g['id'], ' ', $g['created_at'], "\n"; }
$url = !empty($antwort['has_more'])
? 'https://reactive.chat/v1/conversations?status=waiting&limit=100&before_id=' . $antwort['next']['before_id']
: null;
} while ($url);
MCP server
For AI tools that speak the Model Context Protocol, there is an MCP server under the same base:
- Address:
POST https://reactive.chat/v1/mcp(Streamable HTTP, JSON-RPC 2.0, stateless, no batching). The exact address is shown on the API keys page. - Authentication: the same API key as
Authorization: Bearer; the same rate limit. - Protocol versions:
2026-07-28(withserver/discover; the headersMCP-Protocol-Version,Mcp-Methodand, fortools/call,Mcp-Nameare required) as well as2025-11-25,2025-06-18and2025-03-26(withinitialize). - Server only: requests with a browser
Originare rejected with 403.
Tools (tools/list shows only those your key is allowed to use):
- kb_suchen (
read) –projekt,frage(at most 500 characters),n(1–10, default 5). Searches the knowledge base; at most 20 searches per minute and key. - gespraeche_auflisten (
read) –projekt,status,seit(ISO time),limit(at most 100),vor_id. - gespraech_lesen (
read) –id,limit(at most 200, default 100). - nachricht_senden (
write) –gespraech,text(at most 4000 characters), optionallyals(email of an agent who may reply in the project). Delivers immediately as an agent message; the assistant falls silent in this conversation. - wissensluecken (
read) –projekt,stand(offen,erledigt,ignoriert),limit(at most 60).
Without besucherdaten:lesen, visitors' name, email and phone are shortened and personal data in texts is masked. Tool errors come as isError: true with identifiers such as project_not_found, conversation_not_found, conversation_closed, disabled, bad_argument, too_long, search_rate_limited.
Sample entry for an MCP client:
{
"mcpServers": {
"reactive-chat": {
"url": "https://reactive.chat/v1/mcp",
"headers": { "Authorization": "Bearer rc_live_..." }
}
}
}
MCP and the visitor list are new features; they may be switched off per project (the affected project then reports disabled).
What does not exist
- No personal agent tokens and no test keys; all keys are
rc_live_workspace keys. - No endpoints for creating conversations, writing on behalf of visitors or changing project settings, rules or the knowledge base.
- No CORS – the API is not meant for browsers.
Next: Webhooks · Integrations and channels
Zadnje ažuriranje: