Skip to main content
Mavera has migrated from the OpenAI Chat Completions format to the OpenAI Responses API format. This guide walks you through every change — endpoints, SDK methods, request/response shapes, streaming, tool calling, and structured outputs.
The Responses API is not a breaking version bump — it’s a new endpoint format. Your existing Chat Completions code will continue to work during the transition period, but all new features and documentation target the Responses API.

What Changed

ConceptChat Completions (old)Responses API (new)
EndpointPOST /api/v1/chat/completionsPOST /api/v1/responses
SDK methodclient.chat.completions.create()client.responses.create()
Inputmessages: [{role, content}]input: "string" or input: [{role, content}]
System message{role: "system", content: "..."} in messagesinstructions parameter
Output textresponse.choices[0].message.contentresponse.output[0].content[0].text
Streaming (Python)stream=True + for chunk in stream:client.responses.stream() context manager
Streaming (JS)stream: true + for awaitclient.responses.stream() + .on() events
Tool format{type, function: {name, description, parameters}}{type, name, description, parameters} (flat)
Tool call outputresponse.choices[0].message.tool_callsItems in response.output with type == "function_call"
Tool result{role: "tool", tool_call_id, content}{type: "function_call_output", call_id, output}
Structured outputresponse_format: {type, json_schema}text: {format: {type, json_schema}} via extra_body
Parsed outputresponse.choices[0].message.parsedresponse.parsed
Response IDchatcmpl_...resp_...
Response object"chat.completion""response"
Token fieldsprompt_tokens / completion_tokensinput_tokens / output_tokens
Finish signalchoices[0].finish_reason: "stop"status: "completed"
SSE eventsGeneric data: chunksNamed events (response.created, response.output_text.delta, response.completed)
Creditsusage.credits_usedusage.credits_used (no change)

Step-by-Step Migration

1. Update the SDK Method

The SDK method changes from chat.completions.create() to responses.create(). The input format also changes from messages to input. No SDK version change is required — the OpenAI SDK already supports both.
response = client.chat.completions.create(
    model="mavera-1",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "How do Gen Z consumers view sustainability?"}
    ],
    extra_body={"persona_id": "YOUR_PERSONA_ID"},
)
print(response.choices[0].message.content)
const response = await client.chat.completions.create({
  model: "mavera-1",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "How do Gen Z consumers view sustainability?" },
  ],
  persona_id: "YOUR_PERSONA_ID",
});
console.log(response.choices[0].message.content);
curl -X POST https://app.mavera.io/api/v1/chat/completions \
  -H "Authorization: Bearer mvra_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"model": "mavera-1", "persona_id": "YOUR_PERSONA_ID", "messages": [{"role": "user", "content": "..."}]}'

2. Move System Messages to instructions

System messages are no longer part of the messages array. Use the top-level instructions parameter instead. Instructions are appended to the persona’s built-in system prompt.
response = client.chat.completions.create(
    model="mavera-1",
    messages=[
        {"role": "system", "content": "You are a market research analyst."},
        {"role": "user", "content": "Analyze brand loyalty trends."}
    ],
    extra_body={"persona_id": "YOUR_PERSONA_ID"},
)

3. Update Streaming

The streaming interface changes from a flag-based approach to a dedicated stream method with named events.
stream = client.chat.completions.create(
    model="mavera-1",
    messages=[{"role": "user", "content": "Write a product description"}],
    extra_body={"persona_id": "YOUR_PERSONA_ID"},
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
const stream = await client.chat.completions.create({
  model: "mavera-1",
  messages: [{ role: "user", content: "Write a product description" }],
  persona_id: "YOUR_PERSONA_ID",
  stream: true,
});

for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content || "";
  process.stdout.write(delta);
}

4. Update Structured Outputs

The response_format parameter is replaced by text format configuration passed via extra_body. The parsed result moves from response.choices[0].message.parsed to response.parsed.
response = client.chat.completions.create(
    model="mavera-1",
    messages=[{"role": "user", "content": "Review this product: Great quality!"}],
    extra_body={
        "persona_id": "YOUR_PERSONA_ID",
        "response_format": {
            "type": "json_schema",
            "json_schema": {
                "name": "product_review",
                "strict": True,
                "schema": {
                    "type": "object",
                    "properties": {
                        "sentiment": {"type": "string"},
                        "score": {"type": "number"},
                        "summary": {"type": "string"}
                    },
                    "required": ["sentiment", "score", "summary"]
                }
            }
        }
    },
)
data = response.choices[0].message.parsed

5. Update Tool Calling

Tool definitions change from a nested format to a flat format. Tool call results change from {role: "tool"} messages to {type: "function_call_output"} items.

Tool Definitions

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Get the current weather",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"}
                },
                "required": ["location"]
            }
        }
    }
]

Reading Tool Calls

if response.choices[0].finish_reason == "tool_calls":
    for tc in response.choices[0].message.tool_calls:
        print(tc.function.name, tc.function.arguments)

Sending Tool Results

follow_up = client.chat.completions.create(
    model="mavera-1",
    messages=[
        {"role": "user", "content": "What's the weather?"},
        {"role": "assistant", "content": None, "tool_calls": [...]},
        {
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result)
        }
    ],
    extra_body={"persona_id": "YOUR_PERSONA_ID"},
)

6. Update Response Parsing

The response shape changes significantly. Update all code that reads from the response object.
Chat Completions (old)Responses API (new)
response.choices[0].message.contentresponse.output[0].content[0].text
response.choices[0].message.parsedresponse.parsed
response.choices[0].finish_reasonresponse.status
response.usage.prompt_tokensresponse.usage.input_tokens
response.usage.completion_tokensresponse.usage.output_tokens
response.usage.credits_usedresponse.usage.credits_used (unchanged)
response.id (prefix chatcmpl_)response.id (prefix resp_)
response.object ("chat.completion")response.object ("response")

7. Update Error Handling

Error responses use the same format, but the retry logic should reference the new SDK method.
def chat_with_retry(messages, persona_id, max_retries=3):
    for attempt in range(max_retries):
        try:
            return client.chat.completions.create(
                model="mavera-1",
                messages=messages,
                extra_body={"persona_id": persona_id},
            )
        except RateLimitError:
            time.sleep(2 ** attempt)

Migration Checklist

Use this checklist to verify your migration is complete:
  • Replace client.chat.completions.create() with client.responses.create()
  • Replace messages parameter with input parameter
  • Move system messages from messages array to instructions parameter
  • Update streaming to use client.responses.stream() and named events
  • Update response_format to text: {format: {...}} in extra_body
  • Flatten tool definitions (remove function wrapper)
  • Update tool result messages to {type: "function_call_output", call_id, output}
  • Update response parsing: .choices[0].message.content to .output[0].content[0].text
  • Update parsed access: .choices[0].message.parsed to .parsed
  • Update token field references: prompt_tokens to input_tokens, completion_tokens to output_tokens
  • Update finish detection: finish_reason == "stop" to status == "completed"
  • Update cURL endpoints from /chat/completions to /responses
  • Update error handling and retry logic to use new SDK method
  • Test all code paths (basic, streaming, tools, structured outputs, analysis mode)

Common Gotchas

The Responses API does not support {role: "system"} in the input array. Use the instructions parameter instead. If you include a system message in input, it will be ignored or cause an error.
The old {type: "function", function: {name, ...}} nested format will not work. Use the flat format: {type: "function", name: "...", description: "...", parameters: {...}}.
The field name changed from tool_call_id to call_id, and the message type changed from {role: "tool"} to {type: "function_call_output"}.
You can no longer use stream=True as a parameter. Instead, use client.responses.stream() which returns a context manager. Iterate over events and check event.type == 'response.output_text.delta'.
response_format is replaced by text in extra_body. The schema structure inside is the same, but the wrapping key is different: text: {format: {type: "json_schema", json_schema: {...}}}.
There are no more choices — the output is in response.output[]. Each output item has a type field ("message" for text, "function_call" for tool calls). Text content is at response.output[0].content[0].text.
In Python, persona_id is still passed via extra_body. In JavaScript, it’s still a top-level field with // @ts-ignore. This did not change.

See Also

Responses API

Full Responses API reference and usage guide

Migrate OpenAI to Mavera

Migrate from OpenAI to Mavera (base URL + persona)

Streaming Guide

Deep dive into streaming patterns

Function Calling Guide

Tool calling patterns and best practices