Base configuration
| Setting | Value |
|---|---|
| Base URL | https://api.modelriver.com |
| Primary endpoint | POST /v1/ai |
| Async endpoint | POST /v1/ai/async |
| 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
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 for SSE streaming (see Streaming) |
format | ❌ | "raw" (default) or "wrapped" (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.
Response payload
Synchronous response (wrapped format)
1{2 "data": { "summary": "..." },3 "customer_data": { "metadata.audience": "enterprise customers" },4 "meta": {5 "status": "success",6 "http_status": 200,7 "workflow": "marketing_summary",8 "requested_provider": "openai",9 "requested_model": "gpt-4o-mini",10 "used_provider": "openai",11 "used_model": "gpt-4o-mini",12 "duration_ms": 1420,13 "usage": {14 "prompt_tokens": 123,15 "completion_tokens": 45,16 "total_tokens": 16817 },18 "structured_output": true,19 "attempts": [20 {"provider": "openai", "model": "gpt-4o-mini", "status": "success"}21 ]22 },23 "backups": [24 {"position": 1, "provider": "anthropic", "model": "claude-3-5-sonnet"}25 ]26}Response fields explained
| Field | Description |
|---|---|
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 consumption breakdown |
meta.attempts | Array of all provider attempts (including failovers) |
backups | Configured fallback providers for this workflow |
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 "data": null,3 "customer_data": {},4 "error": {5 "message": "Provider request failed",6 "details": {"status": 504, "message": "Upstream timeout"}7 },8 "meta": {9 "status": "error",10 "http_status": 502,11 "workflow": "marketing_summary",12 "attempts": [13 {"provider": "openai", "model": "gpt-4o-mini", "status": "error", "reason": "timeout"}14 ]15 }16}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
- Handle
backupsin the response if you need to know which fallback succeeded - Respect rate limits: if you see
429, implement exponential backoff or reach out to increase limits - Store responses if you need historical context: ModelRiver retains Request Logs, but you can export them or stream them elsewhere
Next steps
- OpenAI SDK compatibility: Use any OpenAI-compatible SDK
- Streaming: Real-time token delivery
- Error handling: Handling failures gracefully
- Webhooks: Receive async results