Skip to content
Get Started

Agent API

Agent API (Responses)

POST /v1/responses — OpenAI Responses-compatible agent surface: client tools, stored conversations, previous_response_id chaining.

POST /v1/responses Create a response
GET /v1/responses/{response_id} Retrieve a stored response
DELETE /v1/responses/{response_id} Delete a stored response; tear down its conversation if it was the last live response
Authorization: Bearer mb_live_*

The Agent API speaks the OpenAI Responses protocol — the recommended way to build agents on Mirobody. It does everything the Answers API does (grounded answers over the Subject’s real health data, server-side tools, reasoning), plus:

  • Client function tools — inject your own tools; the model hands off via function_call output items (Function calling).
  • Stored conversationsstore defaults to true; chain turns with previous_response_id or bind a durable conversation with session_id (State & memory).
  • Standard response.* streaming events (Streaming).

Because it speaks that protocol, the openai-agents SDK needs only a base-URL change:

from agents import Agent, ModelSettings, Runner, set_default_openai_client, set_tracing_disabled
from openai import AsyncOpenAI
set_default_openai_client(AsyncOpenAI(
base_url="https://api.mirobody.ai/v1", api_key="mb_live_..."))
set_tracing_disabled(True) # tracing would call api.openai.com
agent = Agent(name="Health assistant", model="mirobody-flash",
model_settings=ModelSettings(extra_body={"user": "alice"}))
print(Runner.run_sync(agent, "How is my fasting glucose trending?").final_output)

All /v1 endpoints share one base URL — pick the cluster your account uses:

https://api.mirobody.ai/v1 # Global
https://api.mirobody.cn/v1 # China

These are the Cloud clusters. A self-hosted deployment does not expose /v1 — it serves its own /api/* routes and an /mcp endpoint, described in the Self-Host Mirobody.

Japan and EU clusters are in preparation — see Regions. Model providers and pricing can differ by region, so read GET /v1/models from the cluster you call.

Terminal window
curl https://api.mirobody.ai/v1/responses \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mirobody-flash",
"input": "How is my fasting glucose trending?",
"user": "alice"
}'
from openai import OpenAI
client = OpenAI(api_key="mb_live_...", base_url="https://api.mirobody.ai/v1")
resp = client.responses.create(
model="mirobody-flash",
input="How is my fasting glucose trending?",
user="alice",
)
print(resp.output_text)
FieldTypeDescription
modelstringmirobody-flash (default) or mirobody-expert. See Models.
inputstring | arrayRequired. A string (one user turn) or an array of items: message items ({role, content}), and — when continuing a tool handoff — function_call / function_call_output items. See Function calling.
instructionsstringSystem-level instruction for this turn (prepended as a system message).
streambooltrue → SSE of standard response.* events. See Streaming.
storeboolDefault true. Persist the response + conversation: 30-day TTL, or permanent when bound to a session_id. Enables previous_response_id and GET /v1/responses/{id}.
previous_response_idstringContinue the conversation of a stored response (server-side state — no need to resend history). 404 if the id is unknown, expired, or deleted.
session_idstringMirobody extension. Binds this and future turns to a durable named conversation (never auto-expires). Generate a globally unique opaque id (for example a UUID) and never reuse it across Subjects.
toolsarrayClient function tools ({"type": "function", "name", "description", "parameters"}; the completions-nested form is also accepted) and/or remote MCP servers ({"type": "mcp", "server_label", "server_url", …} — executed server-side). Max 64; names must match [a-zA-Z0-9_-]{1,64} and may not shadow built-in tool names. See Function calling · MCP servers.
tool_choicestring | object"auto" (default) / "none" / "required" / a named client tool. "required" and named guarantees apply in backbone mode; the full contract (incl. the 400 cases) is there.
modestring"agent" (default, full server-side agent) or "model" (backbone mode — bare inference, no server tools/state).
builtin_toolsstring | array"auto" (default) / "none" / an allowlist of built-in tool names. Trims the server-side domain tools — see backbone mode.
text.formatobjectStructured output (json_object / json_schema). Backbone mode only — agent mode returns 400. See Structured output.
strictboolWhen true (or header X-Mirobody-Strict: 1), an unknown top-level parameter is rejected with 400 unsupported_parameter instead of being ignored. See Strict validation.
userstringTenant-isolation key → a Subject.
{
"id": "resp_147e9b14c172429a8b19da4be9489243",
"object": "response",
"created_at": 1783741077,
"status": "completed",
"model": "mirobody-flash",
"output": [
{ "type": "reasoning", "id": "rs_0", "status": "completed",
"summary": [{ "type": "summary_text", "text": "..." }] },
{ "type": "message", "id": "msg_0", "status": "completed", "role": "assistant",
"content": [{ "type": "output_text", "text": "Your fasting glucose has trended down ..." }] }
],
"output_text": "Your fasting glucose has trended down ...",
"usage": {
"input_tokens": 9, // YOUR visible input only
"output_tokens": 5,
"total_tokens": 14,
"input_tokens_details": { "system_tokens": 10096, "cached_tokens": 0 },
"output_tokens_details": { "reasoning_tokens": 0 },
"billed_tokens": { "input": 20391, "output": 841, "total": 21232 } // the actual token total you're metered on
},
"tool_steps": [], // Mirobody extension: server tool trace
"health_records": [], // Mirobody extension: {tool, data} evidence
"citations": [], // Mirobody extension: literature evidence
"previous_response_id": null,
"store": true,
"tools": [],
"error": null,
"metadata": {}
}

The output array contains only standard OpenAI item typesreasoning, message, and (on a client-tool handoff) function_call. Official SDKs parse it as-is.

Server-side built-in tool runs are deliberately not output items. The trace rides in the top-level tool_steps extension field ({id, name, arguments, result} — the same shape as the Answers API), which SDKs safely ignore. In streaming it surfaces as the side-channel event response.mirobody_tool_call. health_records and citations carry the evidence the answer used, exactly as on the Answers API.

usage.input_tokens reports the input you actually sent; the platform’s system prompt / tool-schema overhead is broken out as input_tokens_details.system_tokens. output_tokens_details.reasoning_tokens reports provider reasoning tokens. Counts are summed across every model call of the agent turn.

usage.billed_tokens ({input, output, total}) is what you’re metered on — present on both the Agent API and the Answers API. Applying the catalog’s standard input/output rates gives an estimate; prompt-cache discounts can make actual metered cost lower.

Terminal window
curl https://api.mirobody.ai/v1/responses/resp_147e9b14... \
-H "Authorization: Bearer $MIROBODY_API_KEY"

Returns the stored response object. Only store=true responses are retrievable; expired (30-day TTL) or deleted responses return 404.

Terminal window
curl -X DELETE https://api.mirobody.ai/v1/responses/resp_147e9b14... \
-H "Authorization: Bearer $MIROBODY_API_KEY"
{ "id": "resp_147e9b14...", "object": "response.deleted", "deleted": true }

If it was the last live response of its conversation, the whole conversation is torn down too — its history and any conversation-derived memory. That makes this the self-service right-to-be-forgotten lever for stored conversations.

store and retention are orthogonal — one governs the conversation, the other governs the data plane:

KnobApplies toValuesGoverns
storePOST /v1/responsestrue (default) / falseWhether the response object + conversation thread persist: store=true keeps them 30 days (or permanently when bound to a session_id), enabling previous_response_id chaining and GET /v1/responses/{id}. store=false keeps nothing after the reply.
retentionPOST /v1/data, POST /v1/files, POST /v1/standardize (store=true)permanent (alias persistent) / 1d / 6h / 2h / 1h / sessionHow long the health records / files you write live in the Subject’s store. Time grains auto-delete (hard-capped ≤ 24h); session binds records to a session_id and DELETE /v1/sessions/{id} purges them.

retention governs explicit data-plane writes; it does not govern a stored conversation. A stored conversation can also produce health records and memories from its content — delete those with DELETE /v1/data, or erase the Subject. store=false conversations produce none.

Full details — TTLs, chaining semantics, stateless replay, and the cross-session memory that store=true feeds — in State & memory.

By default the surface is lenient (compatibility-first) — an unknown top-level parameter is ignored. Set strict: true in the body or send the header X-Mirobody-Strict: 1 to make it a hard 400 unsupported_parameter instead, with param pointing at the first offending key. Both surfaces (/v1/responses and /v1/chat/completions) honor it. Turn it on while integrating to catch typos and misplaced fields early.

Terminal window
curl https://api.mirobody.ai/v1/responses \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Mirobody-Strict: 1" \
-d '{"model":"mirobody-flash","input":"hi","bogus_param":1,"user":"alice"}'
# → 400 {"error":{"code":"unsupported_parameter","param":"bogus_param", ...}}

Standard error envelope. Surface-specific cases:

HTTPWhen
400Missing/empty input; invalid tools (bad name, reserved name, duplicate, > 64, unsupported type, unreachable MCP server); unsupported tool_choice (see the contract); text.format on agent mode; mode:"model" with previous_response_id/session_id/MCP tools; unknown builtin_tools name; unknown top-level param under strict; malformed handoff continuation (see Function calling)
404Unknown / expired / deleted previous_response_id or response_id
429rate_limit_exceeded (per-key rate limit) or insufficient_quota (monthly account cap) — see Rate Limits & Quota
502Upstream agent error — transient; retry with backoff. In backbone mode provider errors are classified (400 / 429 / 502) rather than a blanket 502.