Base configuration
| Setting | Value |
|---|---|
| Base URL | https://api.modelriver.com |
| Primary endpoint | POST /v1/ai |
| Async endpoint | POST /v1/ai/async |
| Sessions | /v1/sessions: read, extend and follow conversations live (see Sessions API) |
| Usage | GET /v1/usage: the project's billable requests, tokens and cost for a month or a quota cycle (see Usage API) |
| WebSocket | wss://api.modelriver.com/socket, joined with a single-use ws_token |
| Authentication | Authorization: Bearer mr_live_... |
| Content-Type | application/json |
All requests require a valid project API key. Create and manage keys in your project settings.
Synchronous requests
Standard requests return the AI response immediately. Use this for real-time interactions like chatbots, search, or any use case where latency matters.
Use workflow for native ModelRiver requests. For OpenAI-style clients, model may also contain the workflow name; if both are sent, workflow is used.
Endpoint: POST /v1/ai
curl -X POST https://api.modelriver.com/v1/ai \ -H "Authorization: Bearer mr_live_your_key" \ -H "Content-Type: application/json" \ -d '{ "model": "marketing_summary", "messages": [ {"role": "user", "content": "Summarise this week's launch."} ], "metadata": { "audience": "enterprise customers" } }'Python example
1import requests2 3response = requests.post(4 "https://api.modelriver.com/v1/ai",5 headers={6 "Authorization": "Bearer mr_live_your_key",7 "Content-Type": "application/json"8 },9 json={10 "model": "marketing_summary",11 "messages": [12 {"role": "user", "content": "Summarise this week's launch."}13 ]14 }15)16 17data = response.json()18print(data["data"])Node.js example
1const response = await fetch("https://api.modelriver.com/v1/ai", {2 method: "POST",3 headers: {4 "Authorization": "Bearer mr_live_your_key",5 "Content-Type": "application/json",6 },7 body: JSON.stringify({8 model: "marketing_summary",9 messages: [10 { role: "user", content: "Summarise this week's launch." }11 ],12 }),13});14 15const data = await response.json();16console.log(data.data);Asynchronous requests
For long-running tasks (batch processing, complex workflows, backend pipelines), use the async endpoint. It returns the request channel and connection details immediately, and you receive the result via WebSocket or webhook.
The async endpoint accepts the same workflow selection fields as the sync endpoint: use workflow, or use model as the workflow-name alias.
Endpoint: POST /v1/ai/async
curl -X POST https://api.modelriver.com/v1/ai/async \ -H "Authorization: Bearer mr_live_your_key" \ -H "Content-Type: application/json" \ -d '{ "model": "batch_processor", "messages": [ {"role": "user", "content": "Process this large document..."} ] }'Async response (immediate)
1{2 "message": "success",3 "status": "pending",4 "channel_id": "550e8400-e29b-41d4-a716-446655440000",5 "session_id": null,6 "ws_token": "single-use-websocket-token",7 "websocket_url": "wss://api.modelriver.com/socket",8 "websocket_channel": "ai_response:project-uuid:550e8400-e29b-41d4-a716-446655440000"9}session_id is a UUID when the selected workflow has session memory enabled; otherwise it is null.
WebSocket flow
- Connect to the WebSocket URL with your
ws_token - Join the channel
ai_response:{project_id}:{channel_id} - Listen for
responseevents containing the final payload
With "stream": true, the answer also arrives token by token before the final response: stream_start, then stream_delta events, then stream_done (or stream_error). See Streaming over WebSocket.
To follow a whole conversation rather than one request (new turns as they're stored, including human-agent replies), subscribe to its session: see Live updates.
Tip: Use the official Client SDK to handle WebSocket connections, reconnection, and progress tracking automatically.
Request fields
| Field | Required | Description |
|---|---|---|
workflow | ✅* | Name of a saved workflow. Preferred for native API requests and used when both workflow and model are sent |
provider | ❌ | Provider name (required when not using workflows) |
model | ✅* | Workflow-name alias for OpenAI-style clients when workflow is not sent |
messages | ✅ | Chat-style payload: array of {role, content} objects |
temperature | ❌ | Sampling temperature (0–2), passed to provider |
max_tokens | ❌ | Maximum tokens in response |
top_p | ❌ | Nucleus sampling parameter |
stream | ❌ | true streams the answer token by token: as SSE from /v1/ai, as WebSocket stream_* events from /v1/ai/async (see Streaming) |
format | ❌ | Accepted for backward compatibility but has no effect; /v1/ai always returns the response envelope shown below (see Response formats) |
response_format | ❌ | JSON schema for structured output (or use workflow's schema) |
structured_output_schema | ❌ | Pass a JSON schema directly without creating a workflow |
tools | ❌ | Array of tool definitions for function calling |
tool_choice | ❌ | How the model should use tools (auto, none, etc.) |
inputs | ❌ | Free-form fields your workflow can access |
metadata | ❌ | Free-form metadata (echoed via cache fields) |
context | ❌ | Additional context passed to the provider |
session_id | ❌ | Conversation grouping for workflows with session memory enabled (see below) |
* Provide either workflow or model to select a saved workflow.
Session memory (session_id)
When a workflow has Session memory enabled (Advanced settings, off by default), requests can be grouped into conversations:
- Start a conversation — send a request without
session_id. The server creates a session and returns the id inmeta.session_idfor synchronous requests, as the top-levelsession_idfor asynchronous requests, or in the first SSE metadata event for streaming requests. - Continue the conversation — send the current turn only. Do not accumulate
the
messagesarray client-side; the server merges memory (recent raw history, then a rolling summary) itself.
1// First turn2{ "workflow": "my_chatbot", "messages": [{ "role": "user", "content": "My order is 1234" }] }3 4// Second turn — same session, current turn only5{6 "workflow": "my_chatbot",7 "session_id": "9f8c…-uuid-from-first-response",8 "messages": [{ "role": "user", "content": "Cancel it please" }]9}Notes:
session_idis a grouping identifier only — it is identical for every turn of the conversation and is not used for request correlation or callback correlation (channel_id/request_log_idhandle those).- The conversation memory is summarized lazily at ~2000-token boundaries; the
summarization appears in Request Logs as a
session_summaryentry. - Session requests bypass the response cache, so enable it on workflows where conversation continuity matters more than cache hits.
- OpenAI-compatible endpoints accept
session_idin the request body and return it in thex-modelriver-session-idresponse header. - A
session_idthat does not belong to the project/workflow returns422 session_not_found. Delete sessions (reset memory) in the console under Logs → Sessions, or with the Sessions API. - Read conversations, add human-agent turns without calling a model, or follow a conversation live over WebSockets, with the Sessions API.
Response payload
Synchronous response
1{2 "message": "success",3 "status": "success",4 "data": { "summary": "..." },5 "customer_data": { "metadata.audience": "enterprise customers" },6 "meta": {7 "status": "success",8 "http_status": 200,9 "workflow": "marketing_summary",10 "requested_provider": "openai",11 "requested_model": "gpt-4o-mini",12 "used_provider": "openai",13 "used_model": "gpt-4o-mini",14 "duration_ms": 1420,15 "usage": {16 "prompt_tokens": 123,17 "completion_tokens": 45,18 "total_tokens": 168,19 "cache_read_tokens": 0,20 "cache_write_tokens": 0,21 "cache_write_1h_tokens": 0,22 "reasoning_tokens": 023 },24 "structured_output": true,25 "attempts": [26 {"provider": "openai", "model": "gpt-4o-mini", "status": "success"}27 ]28 }29}Response fields explained
| Field | Description |
|---|---|
status | "success" or "error" |
data | The AI-generated response content |
customer_data | Cached fields echoed from your request metadata |
meta.status | "success" or "error" |
meta.workflow | The workflow that processed this request |
meta.used_provider | The provider that actually served the response |
meta.duration_ms | End-to-end request duration in milliseconds |
meta.usage | Token counts: prompt_tokens (all input, cached included), completion_tokens (all output, reasoning included), total_tokens, and the provider cache and reasoning parts of them |
meta.attempts | Array of all provider attempts (including failovers) |
Error responses
ModelRiver returns 200 with an error object when the request was valid but the provider failed. Transport/authentication problems return standard HTTP status codes (401, 403, 429, 5xx).
1{2 "status": "error",3 "message": "Provider request failed",4 "customer_data": {},5 "error": {6 "message": "Provider request failed",7 "details": {"status": 504, "message": "Upstream timeout"}8 },9 "meta": {10 "status": "error",11 "http_status": 502,12 "workflow": "marketing_summary",13 "attempts": [14 {"provider": "openai", "model": "gpt-4o-mini", "status": "error", "reason": "timeout"}15 ]16 }17}For complete error handling details, see Error handling.
Tips for production use
- Use workflows so you can change providers and prompts without redeploying applications
- Leverage cache fields to echo request metadata in responses: especially helpful for tracing user IDs or experiment variants
- Check
meta.used_providerandmeta.attemptsif you need to know whether a fallback served the response - Respect rate limits: if you see
429, implement exponential backoff or reach out to increase limits - Read conversations back with the Sessions API when the workflow uses session memory. Logs may be deleted after your plan's retention period, so save anything else you need (or anything you must keep longer) in your own systems. On Scale and Custom plans you can also download request logs as CSV or JSONL
Next steps
- Sessions API: Read, extend and follow session-memory conversations live
- OpenAI SDK compatibility: Use any OpenAI-compatible SDK
- Streaming: Real-time token delivery
- Error handling: Handling failures gracefully
- Webhooks: Receive async results