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.

🌐
API Base URL
https://gateway.motai.ai
💬
Chat Completions
Real-time streaming AI responses with memory context automatically injected.
🧠
Persistent Memory
Semantic search over user memory so every conversation feels continuous.
📤
Extraction
Submit conversation transcripts to extract structured insights and store memories.
🔐
API Key Auth
Simple Bearer token authentication. Generate and manage keys from your dashboard.

Make your first API call in 3 steps

Get up and running with MOTAI in under 5 minutes.

Get an API key
Sign in to your MOTAI Dashboard, navigate to API Keys, and create a new key. Copy it — you won't see it again.
Send a chat request
Use the key as a Bearer token in the Authorization header:
bash
# 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"
  }'
Handle the streaming response
The API responds with Server-Sent Events (SSE). Each chunk contains a partial response delta.
SSE response
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]
That's it. MOTAI automatically retrieves relevant memories for 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.

HTTP Header
Authorization: Bearer motai_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
⚠️ Keep your API key secret. Never expose it in client-side code, public repositories, or logs. If a key is compromised, revoke it immediately from your Dashboard.

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?

JSON — 401 Unauthorized
{
  "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.

POST /v1/chat Requires auth · Streams SSE

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].

bash
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"
  }'
javascript
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 ?? '');
  });
}
python
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.

GET /v1/memory Requires auth

Query parameters

ParameterTypeRequiredDescription
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

JSON
{
  "memories": [
    {
      "id": "mem_abc123",
      "memory": "User prefers concise answers",
      "score": 0.94,
      "created_at": "2026-06-21T17:00:00Z"
    }
  ]
}
bash
curl "https://gateway.motai.ai/v1/memory?query=user+preferences&user_external_id=user-123" \
  -H "Authorization: Bearer YOUR_API_KEY"
javascript
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);
python
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.

POST /v1/extract Requires auth

Request body

ParameterTypeRequiredDescription
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".
bash
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." }
    ]
  }'
javascript
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!' },
    ],
  }),
});
python
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.

GET /health No auth required

Response — 200 OK

JSON
{
  "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.

bash
curl https://gateway.motai.ai/health
javascript
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].

SSE Stream
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]
ℹ️ When using 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.js
// 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

python
"""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.

Requests per minute
60 req/min
Max body size
512 KB
Memory timeout
10 seconds
Extract timeout
10 seconds

429 Too Many Requests

When you exceed the rate limit the gateway returns:

HTTP 429
{
  "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.

200
OK
Request succeeded.
400
Bad Request
Missing or invalid parameters. Check the error field for details.
401
Unauthorized
API key is missing, malformed, or invalid.
403
Forbidden
Valid key but insufficient permissions for this operation.
429
Too Many Requests
Rate limit exceeded. Wait 1 minute before retrying.
500
Internal Error
Unexpected server error. Check /health for service status.
502
Bad Gateway
An internal service (AI model, memory, extractor) returned an error or timed out.
503
Service Unavailable
One or more internal dependencies are down. See /health for details.

Error response format

JSON
{
  "error": "query parameter is required"
}

Changelog

v1.0.0 June 2026 Current
  • 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 context field
v1.1.0 Coming soon Planned
  • 🔜 Token management panel in Dashboard (generate, revoke, audit)
  • 🔜 Usage analytics per API key
  • 🔜 Webhook support for async extraction results