ModelRiver supports two response formats. By default, responses are returned in raw format for maximum compatibility with existing OpenAI/Anthropic clients.
Raw format (default)
Returns the exact provider response, maintaining full compatibility with OpenAI/Anthropic SDKs.
Request:
1{2 "workflow": "my-chat-workflow",3 "messages": [4 {"role": "user", "content": "Hello!"}5 ]6}Response:
1{2 "id": "chatcmpl-123",3 "object": "chat.completion",4 "created": 1677652288,5 "model": "gpt-4o",6 "choices": [7 {8 "index": 0,9 "message": {10 "role": "assistant",11 "content": "Hello! How can I help you today?"12 },13 "finish_reason": "stop"14 }15 ],16 "usage": {17 "prompt_tokens": 9,18 "completion_tokens": 12,19 "total_tokens": 2120 }21}Metadata in headers
When using raw format, ModelRiver returns metadata via HTTP headers:
| Header | Description |
|---|---|
X-ModelRiver-Provider | The provider used (e.g., openai, anthropic) |
X-ModelRiver-Model | The model used (e.g., gpt-4o) |
X-ModelRiver-Workflow | The workflow name |
X-ModelRiver-Duration-Ms | Request duration in milliseconds |
X-ModelRiver-Attempts | Number of provider attempts (includes fallbacks) |
X-ModelRiver-Cached-Data | Cached fields (JSON string) |
X-ModelRiver-Offline-Fallback | "true" if offline fallback was used |
When to use raw format
✅ Drop-in replacement: Replace OpenAI/Anthropic calls without changing client code ✅ SDK compatibility: Works with existing OpenAI/Anthropic SDKs ✅ Minimal overhead: Fastest response with minimal data transfer ✅ Standard integration: Apps that expect standard provider response format
Wrapped format
Returns the provider response wrapped with additional ModelRiver metadata, logs, and cached data.
Request:
1{2 "workflow": "my-chat-workflow",3 "format": "wrapped",4 "messages": [5 {"role": "user", "content": "Hello!"}6 ]7}Response:
1{2 "data": {3 "id": "chatcmpl-123",4 "object": "chat.completion",5 "created": 1677652288,6 "model": "gpt-4o",7 "choices": [8 {9 "index": 0,10 "message": {11 "role": "assistant",12 "content": "Hello! How can I help you today?"13 },14 "finish_reason": "stop"15 }16 ],17 "usage": {18 "prompt_tokens": 9,19 "completion_tokens": 12,20 "total_tokens": 2121 }22 },23 "customer_data": {24 "user_id": "550e8400-e29b-41d4-a716-446655440000"25 },26 "meta": {27 "status": "success",28 "http_status": 200,29 "workflow": "my-chat-workflow",30 "requested_provider": "openai",31 "requested_model": "gpt-4o",32 "used_provider": "openai",33 "used_model": "gpt-4o",34 "duration_ms": 1250,35 "usage": {36 "prompt_tokens": 9,37 "completion_tokens": 12,38 "total_tokens": 2139 },40 "structured_output": false,41 "attempts": [42 {43 "provider": "openai",44 "model": "gpt-4o",45 "status": "success"46 }47 ],48 "customer_fields": ["user_id"]49 },50 "logs": {51 "columns": [],52 "rows": []53 },54 "backups": [55 {56 "position": 1,57 "provider": "anthropic",58 "model": "claude-3-5-sonnet"59 }60 ]61}When to use wrapped format
✅ Debugging: Detailed request logs and metadata ✅ Monitoring: Track provider fallbacks and attempts ✅ Analytics: Access cached data for analysis ✅ Internal tools: Building consoles or admin interfaces ✅ Audit trails: Compliance requirements with detailed logging
Usage examples
JavaScript (raw format)
1const response = await fetch("https://api.modelriver.com/v1/ai", {2 method: "POST",3 headers: {4 Authorization: "Bearer YOUR_API_KEY",5 "Content-Type": "application/json",6 },7 body: JSON.stringify({8 workflow: "my-chat-workflow",9 messages: [{ role: "user", content: "Hello!" }],10 }),11});12 13const data = await response.json();14// data is exactly like OpenAI's response15console.log(data.choices[0].message.content);16 17// Check headers for metadata18const provider = response.headers.get("X-ModelRiver-Provider");19const duration = response.headers.get("X-ModelRiver-Duration-Ms");20console.log(`Completed in ${duration}ms using ${provider}`);Python (raw format with OpenAI SDK)
1import openai2 3client = openai.OpenAI(4 base_url="https://api.modelriver.com/v1",5 api_key="YOUR_API_KEY"6)7 8response = client.chat.completions.create(9 model="my-chat-workflow",10 messages=[{"role": "user", "content": "Hello!"}]11)12 13print(response.choices[0].message.content)cURL (wrapped format)
curl -X POST https://api.modelriver.com/v1/ai \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "workflow": "my-chat-workflow", "format": "wrapped", "messages": [ {"role": "user", "content": "Hello!"} ] }'TypeScript type definitions
1// Raw Format (OpenAI-compatible)2interface RawResponse {3 id: string;4 object: string;5 created: number;6 model: string;7 choices: Array<{8 index: number;9 message: { role: string; content: string };10 finish_reason: string;11 }>;12 usage: {13 prompt_tokens: number;14 completion_tokens: number;15 total_tokens: number;16 };17}18 19// Wrapped Format20interface WrappedResponse {21 data: RawResponse;22 customer_data: Record<string, any>;23 meta: {24 status: string;25 http_status: number;26 workflow: string;27 requested_provider: string;28 requested_model: string;29 used_provider: string;30 used_model: string;31 duration_ms: number;32 usage: {33 prompt_tokens: number;34 completion_tokens: number;35 total_tokens: number;36 };37 structured_output: boolean;38 attempts: Array<{39 provider: string;40 model: string;41 status: string;42 reason?: any;43 }>;44 customer_fields: string[];45 };46 logs: { columns: Array<{ key: string; label: string }>; rows: any[] };47 backups: Array<{ position: number; provider: string; model: string }>;48}Error handling
Errors are always returned in wrapped format, regardless of the format parameter, since there's no standard provider error format. See Error handling for complete details.
Comparison
| Aspect | Raw Format | Wrapped Format |
|---|---|---|
| Default | ✅ Yes | ❌ No |
| Provider compatibility | ✅ Full | ❌ Custom |
| Metadata location | Headers | Response body |
| Response size | Smaller | Larger |
| Use case | Production | Debugging/Analytics |
| SDK support | ✅ Yes | ❌ Manual parsing |
Best practices
- Default to raw format for production applications
- Use wrapped format during development and debugging
- Check response headers for metadata without payload overhead
- Cache workflow names to avoid repeated console lookups
- Monitor
X-ModelRiver-Attemptsto detect fallback patterns - Log
X-ModelRiver-Offline-Fallbackto identify connectivity issues
Next steps
- Error handling: Complete error reference
- Endpoints: Full endpoint specification
- OpenAI compatibility: SDK integration