Documentation

Raw or wrapped: choose your response format

Raw format for drop-in SDK compatibility. Wrapped format for full metadata, logs, and debugging. Choose the right one for your use case.

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:

JSON
1{
2 "workflow": "my-chat-workflow",
3 "messages": [
4 {"role": "user", "content": "Hello!"}
5 ]
6}

Response:

JSON
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": 21
20 }
21}

Metadata in headers

When using raw format, ModelRiver returns metadata via HTTP headers:

HeaderDescription
X-ModelRiver-ProviderThe provider used (e.g., openai, anthropic)
X-ModelRiver-ModelThe model used (e.g., gpt-4o)
X-ModelRiver-WorkflowThe workflow name
X-ModelRiver-Duration-MsRequest duration in milliseconds
X-ModelRiver-AttemptsNumber of provider attempts (includes fallbacks)
X-ModelRiver-Cached-DataCached 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:

JSON
1{
2 "workflow": "my-chat-workflow",
3 "format": "wrapped",
4 "messages": [
5 {"role": "user", "content": "Hello!"}
6 ]
7}

Response:

JSON
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": 21
21 }
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": 21
39 },
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)

JAVASCRIPT
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 response
15console.log(data.choices[0].message.content);
16 
17// Check headers for metadata
18const 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)

PYTHON
1import openai
2 
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)

Bash
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

TYPESCRIPT
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 Format
20interface 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

AspectRaw FormatWrapped Format
Default✅ Yes❌ No
Provider compatibility✅ Full❌ Custom
Metadata locationHeadersResponse body
Response sizeSmallerLarger
Use caseProductionDebugging/Analytics
SDK support✅ Yes❌ Manual parsing

Best practices

  1. Default to raw format for production applications
  2. Use wrapped format during development and debugging
  3. Check response headers for metadata without payload overhead
  4. Cache workflow names to avoid repeated console lookups
  5. Monitor X-ModelRiver-Attempts to detect fallback patterns
  6. Log X-ModelRiver-Offline-Fallback to identify connectivity issues

Next steps