MOTAI API Reference
MOTAI is an AI platform that exposes OpenAI-compatible endpoints for chat, persistent memory, and conversation extraction. You can integrate MOTAI into any application using a standard Bearer token and plain HTTP requests.
Make your first API call in 3 steps
Get up and running with MOTAI in under 5 minutes.
# Replace YOUR_API_KEY with your actual key curl -X POST https://gateway.motai.ai/v1/chat \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ --no-buffer \ -d '{ "message": "Hello, who are you?", "user_external_id": "user-123" }'
data: {"id":"chatcmpl-abc","choices":[{"delta":{"role":"assistant","content":"Hello"}}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"! I'm"}}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":" Motai"}}]} data: [DONE]
user-123 and injects them as context before sending the request to the AI model.
Authenticating requests
All API endpoints (except /health) require a valid API key sent as a Bearer token in the Authorization header.
Authorization: Bearer motai_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API key format
MOTAI API keys follow the format motai_sk_ followed by a 32-character alphanumeric string. Keys are tied to a vertical (your product line) and scoped to rate limits defined in your plan.
Key verification
Every request passes through an LRU-cached credential verification layer (500 entries, 60-second TTL). This means your key is validated in milliseconds on warm requests — no database hit on every call.
What happens on auth failure?
{ "error": "Unauthorized" }
Chat Completions
Send a message and receive a real-time streaming AI response. MOTAI automatically retrieves relevant memories for the specified user and injects them as context.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| message | string | required | The user's message text. |
| user_external_id | string | optional | Your internal user ID. Used to scope memory retrieval. Defaults to "anonymous". |
| context | string | optional | Extra context to inject into the system prompt. Max 500 characters. Control characters are stripped. |
| vertical_code | string | optional | Override the vertical code derived from your API key. Used for multi-product setups. |
Response
Returns a text/event-stream (SSE) of OpenAI-compatible delta chunks followed by data: [DONE].
curl -X POST https://gateway.motai.ai/v1/chat \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ --no-buffer \ -d '{ "message": "Summarize our last conversation", "user_external_id": "user-123", "context": "User is on the premium plan" }'
const response = await fetch('https://gateway.motai.ai/v1/chat', { method: 'POST', headers: { 'Authorization': `Bearer ${YOUR_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ message: 'Summarize our last conversation', user_external_id: 'user-123', }), }); const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value); // parse SSE lines chunk.split('\n').forEach(line => { if (!line.startsWith('data: ')) return; const raw = line.slice(6); if (raw === '[DONE]') return; const data = JSON.parse(raw); process.stdout.write(data.choices[0]?.delta?.content ?? ''); }); }
import requests import json response = requests.post( "https://gateway.motai.ai/v1/chat", headers={ "Authorization": f"Bearer {YOUR_API_KEY}", "Content-Type": "application/json", }, json={ "message": "Summarize our last conversation", "user_external_id": "user-123", }, stream=True, ) for line in response.iter_lines(): if not line or not line.startswith(b"data: "): continue raw = line[6:] if raw == b"[DONE]": break data = json.loads(raw) content = data["choices"][0]["delta"].get("content", "") print(content, end="", flush=True)
Memory Search
Perform a semantic search over a user's stored memories. Returns the top 10 most relevant memory entries. Memory is automatically scoped to your vertical — users from different products can never cross-query each other's data.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| query | string | required | Natural language query to search memories semantically. |
| user_external_id | string | optional | The user whose memories to search. Defaults to "anonymous". |
Response
{ "memories": [ { "id": "mem_abc123", "memory": "User prefers concise answers", "score": 0.94, "created_at": "2026-06-21T17:00:00Z" } ] }
curl "https://gateway.motai.ai/v1/memory?query=user+preferences&user_external_id=user-123" \ -H "Authorization: Bearer YOUR_API_KEY"
const params = new URLSearchParams({ query: 'user preferences', user_external_id: 'user-123', }); const res = await fetch(`https://gateway.motai.ai/v1/memory?${params}`, { headers: { 'Authorization': `Bearer ${YOUR_API_KEY}` }, }); const { memories } = await res.json(); console.log(memories);
res = requests.get( "https://gateway.motai.ai/v1/memory", headers={"Authorization": f"Bearer {YOUR_API_KEY}"}, params={"query": "user preferences", "user_external_id": "user-123"}, ) memories = res.json()["memories"]
Conversation Extraction
Submit a full conversation transcript after it ends. MOTAI analyzes it, extracts structured insights (preferences, facts, intents), and stores them as memories for future conversations. Timeout: 10 seconds.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| conversation_id | string | required | Unique ID for this conversation. |
| transcript | array | required | Array of { role, content } objects. Roles: user, assistant, system. |
| user_external_id | string | optional | Maps extracted memories to this user. Defaults to "unknown". |
| company_uid | string | optional | UUID of the company account. |
| channel | string | optional | Source channel (e.g. "api", "web", "mobile"). Defaults to "api". |
curl -X POST https://gateway.motai.ai/v1/extract \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "conversation_id": "conv-20260621-001", "user_external_id": "user-123", "channel": "api", "transcript": [ { "role": "user", "content": "I prefer dark mode interfaces" }, { "role": "assistant", "content": "Noted! I will remember that preference." } ] }'
await fetch('https://gateway.motai.ai/v1/extract', { method: 'POST', headers: { 'Authorization': `Bearer ${YOUR_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ conversation_id: 'conv-20260621-001', user_external_id: 'user-123', transcript: [ { role: 'user', content: 'I prefer dark mode' }, { role: 'assistant', content: 'Noted!' }, ], }), });
requests.post( "https://gateway.motai.ai/v1/extract", headers={"Authorization": f"Bearer {YOUR_API_KEY}"}, json={ "conversation_id": "conv-20260621-001", "user_external_id": "user-123", "transcript": [ {"role": "user", "content": "I prefer dark mode"}, {"role": "assistant", "content": "Noted!"}, ], }, )
Health Check
Returns the operational status of the gateway and its internal dependencies. This endpoint does not require authentication and is safe to call from monitoring tools.
Response — 200 OK
{ "status": "ok", "version": "1.0.0", "uptime": 86400 }
When any internal service is unhealthy the HTTP status becomes 503 and status returns "degraded". Chat requests may still succeed if the AI model is operational.
curl https://gateway.motai.ai/health
const { status } = await fetch('https://gateway.motai.ai/health') .then(r => r.json()); console.log(status); // "ok" or "degraded"
Server-Sent Events (SSE)
The POST /v1/chat endpoint always streams responses using the Server-Sent Events protocol. This means you receive tokens as they are generated, dramatically reducing perceived latency.
SSE format
Each line is prefixed with data: . The final message is the sentinel data: [DONE].
data: {"id":"chatcmpl-abc","choices":[{"delta":{"role":"assistant","content":""}}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Hello"}}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"!"}}]} data: {"id":"chatcmpl-abc","choices":[{"finish_reason":"stop"}]} data: [DONE]
curl, add --no-buffer to see tokens as they arrive. In Node.js use response.body.getReader(). In browsers use the native EventSource API or fetch with ReadableStream.
Using EventSource (browser)
EventSource only supports GET and cannot send custom headers. Use fetch with a ReadableStream to set the Authorization header from a browser.
SDK Examples
MOTAI is compatible with any HTTP client. Below are complete, copy-paste examples for common use cases.
Node.js — Chat with streaming
// node motai-chat.mjs const API_KEY = 'motai_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; async function chat(message, userId) { const res = await fetch('https://gateway.motai.ai/v1/chat', { method: 'POST', headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ message, user_external_id: userId }), }); const reader = res.body.getReader(); const dec = new TextDecoder(); process.stdout.write('\nMotai: '); while (true) { const { done, value } = await reader.read(); if (done) break; dec.decode(value).split('\n').forEach(line => { if (!line.startsWith('data: ')) return; const raw = line.slice(6); if (raw === '[DONE]') { process.stdout.write('\n'); return; } try { const d = JSON.parse(raw); process.stdout.write(d.choices[0]?.delta?.content ?? ''); } catch {} }); } } chat('What can you help me with?', 'user-123');
Python — Full pipeline
"""Chat → Extract → Verify memory.""" import requests, json API_KEY = "motai_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" BASE = "https://gateway.motai.ai" HEADERS = {"Authorization": f"Bearer {API_KEY}"} USER_ID = "user-123" # 1. Chat (collect full response) message = "I always drink oat milk in my coffee" response = requests.post( f"{BASE}/v1/chat", headers={**HEADERS, "Content-Type": "application/json"}, json={"message": message, "user_external_id": USER_ID}, stream=True, ) full_reply = "" for line in response.iter_lines(): if not line or not line.startswith(b"data: "): continue raw = line[6:] if raw == b"[DONE]": break full_reply += json.loads(raw)["choices"][0]["delta"].get("content", "") # 2. Extract insights from the conversation requests.post( f"{BASE}/v1/extract", headers={**HEADERS, "Content-Type": "application/json"}, json={ "conversation_id": "conv-001", "user_external_id": USER_ID, "transcript": [ {"role": "user", "content": message}, {"role": "assistant", "content": full_reply}, ], }, ) # 3. Verify memory was stored mems = requests.get( f"{BASE}/v1/memory", headers=HEADERS, params={"query": "coffee preferences", "user_external_id": USER_ID}, ).json()["memories"] print(mems)
Rate Limits
Rate limits are enforced per API key using a sliding-window counter. Keys are identified by the first 33 characters of the Bearer token. IP-based limiting applies when no valid token is present.
429 Too Many Requests
When you exceed the rate limit the gateway returns:
{ "statusCode": 429, "error": "Too Many Requests", "message": "Rate limit exceeded, retry in 1 minute" }
Implement exponential backoff starting at 1 second when you receive a 429.
Error Reference
MOTAI uses standard HTTP status codes. All error responses have a JSON body with an error field.
error field for details./health for service status./health for details.Error response format
{ "error": "query parameter is required" }
Changelog
- ✅
POST /v1/chat— streaming SSE chat with memory context injection - ✅
GET /v1/memory— semantic memory search (top 10, scoped per vertical) - ✅
POST /v1/extract— conversation insight extraction and memory storage - ✅
GET /health— public health check endpoint - ✅ Bearer token auth with LRU credential cache (500 entries, 60 s TTL)
- ✅ Per-vertical rate limiting (60 req/min)
- ✅ IDOR protection: user IDs namespaced by vertical code
- ✅ Prompt injection mitigation on
contextfield
- 🔜 Token management panel in Dashboard (generate, revoke, audit)
- 🔜 Usage analytics per API key
- 🔜 Webhook support for async extraction results