Skip to main content

Endpoint

POST   /v1/responses                Create a response
GET    /v1/responses/{response_id}  Retrieve a stored response
DELETE /v1/responses/{response_id}  Delete a stored response (+ its conversation)
Authorization: Bearer mb_live_*
The Agent API is Mirobody’s OpenAI Responses API-compatible surface — the recommended way to build agents on Mirobody. 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 the Responses protocol, the openai-agents SDK works against it by changing only the base URL — verified live:
from agents import Agent, Runner, set_default_openai_client, set_tracing_disabled
from openai import AsyncOpenAI

set_default_openai_client(AsyncOpenAI(
    base_url="https://test-mirobody-api.thetahealth.ai/v1", api_key="mb_live_..."))
set_tracing_disabled(True)   # tracing would call api.openai.com

agent = Agent(name="Health assistant", model="mirobody-flash")
print(Runner.run_sync(agent, "How is my fasting glucose trending?").final_output)
The live integration environment today is the global test cluster:
https://test-mirobody-api.thetahealth.ai/v1
Its data is non-production and may be reset at any time — never put real end-user data there. See Regions for the full host matrix and live status.

Create a response

curl https://test-mirobody-api.thetahealth.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://test-mirobody-api.thetahealth.ai/v1")

resp = client.responses.create(
    model="mirobody-flash",
    input="How is my fasting glucose trending?",
    user="alice",
)
print(resp.output_text)

Request body

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).
toolsarrayClient function tools ({"type": "function", "name", "description", "parameters"}; the completions-nested form is also accepted). Max 64; names must match [a-zA-Z0-9_-]{1,64} and may not shadow built-in tool names. See Function calling.
tool_choicestring | object"auto" (default) / "none" / a named client tool. Anything else → 400 unsupported_parameter.
userstringTenant-isolation key → a Subject.
The user field is the tenant-isolation key. The backend maps (your account, user) to an internal Subject; each user you pass is fully isolated from the others. Pass each end-user’s stable id and their data never crosses over. Omit it and the call falls back to your account’s default Subject. Subjects are invisible to the Mirobody consumer app and to other developers.

Response object

{
  "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 }
  },
  "tool_steps": [],                                      // Mirobody extension: server tool trace
  "health_records": [],                                  // Mirobody extension: {tool, data} evidence
  "citations": [],                                       // Mirobody extension: literature evidence
  "previous_response_id": null,
  "store": false,
  "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 accounting

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 counts thinking tokens. Counts are summed across every model call of the agent turn.

Retrieve a stored response

curl https://test-mirobody-api.thetahealth.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.

Delete a stored response

curl -X DELETE https://test-mirobody-api.thetahealth.ai/v1/responses/resp_147e9b14... \
  -H "Authorization: Bearer $MIROBODY_API_KEY"
{ "id": "resp_147e9b14...", "object": "response.deleted", "deleted": true }
Deletes the stored response. If it was the last live response of its conversation, the whole conversation is torn down too — chat projection, agent thread state, and any conversation-derived memory. This is the self-service right-to-be-forgotten lever for stored conversations.

State model

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/extract (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.
A stored conversation (store=true) does not persist any health data by itself, and permanent health records don’t keep a conversation alive. Combine them as needed: e.g. store=false + retention=1h for a fully ephemeral run, or session_id-bound responses + retention=session data for a durable conversation whose working data dies with the session. Full details — TTLs, chaining semantics, stateless replay, and the cross-session memory that store=true feeds — in State & memory.

Errors

Standard error envelope. Surface-specific cases:
HTTPWhen
400Missing/empty input; invalid tools (bad name, reserved name, duplicate, > 64, non-function type); unsupported tool_choice; malformed handoff continuation (see Function calling)
404Unknown / expired / deleted previous_response_id or response_id
502Upstream agent error — transient; retry with backoff