Invoke Kindo agents with the Responses API
Every agent you build in Kindo is invocable through
POST /v1/responses by passing its ID as the model:
{ "model": "agent/8e051857-978c-4207-8916-28a3d4c4d605", "input": "..." }The agent supplies the model, system prompt, and tools; you supply
the task. Because model is a field every OpenAI Responses client
can set, this works from stock SDKs with no code changes — the same
clients you already point at api.kindo.ai.
This page takes you from zero to a streamed agent run.
What you need
Section titled “What you need”-
A Kindo API key — see Authentication.
-
Your agent’s ID. Two ways to find it:
Terminal window # Alongside your model catalog (agents appear as agent/<agent-id>)curl "https://api.kindo.ai/v1/models?include_agents=true" \-H "Authorization: Bearer $KINDO_API_KEY"# Or from the agents list (returns agentId per agent)curl https://api.kindo.ai/v1/agents/list \-H "Authorization: Bearer $KINDO_API_KEY"You can also copy the agent ID from its URL in the Kindo Terminal.
Invoke the agent
Section titled “Invoke the agent”openai-python
Section titled “openai-python”import osfrom openai import OpenAI
client = OpenAI( base_url="https://api.kindo.ai/v1", api_key=os.environ["KINDO_API_KEY"],)
response = client.responses.create( model="agent/8e051857-978c-4207-8916-28a3d4c4d605", input="Triage INC-4821 and propose a remediation plan.", instructions="Keep the summary to one sentence.", # optional — appends after the agent's own prompt)
print(response.id, response.status)# resp_run_04f0faa6-2e66-4f5a-b49f-6a28daa58d9b in_progresscurl -X POST https://api.kindo.ai/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $KINDO_API_KEY" \ -d '{ "model": "agent/8e051857-978c-4207-8916-28a3d4c4d605", "input": "Triage INC-4821 and propose a remediation plan." }'The call returns immediately with an in-progress response — agent runs are long-horizon, so you stream or poll rather than block:
{ "id": "resp_run_04f0faa6-2e66-4f5a-b49f-6a28daa58d9b", "object": "response", "status": "in_progress", "model": "agent/8e051857-978c-4207-8916-28a3d4c4d605", "output": [], "conversation": { "id": "conv_cmqbjvxqv000001ac25z0pje6" }, "metadata": { "kindo_run_id": "04f0faa6-2e66-4f5a-b49f-6a28daa58d9b", "kindo_agent_id": "8e051857-978c-4207-8916-28a3d4c4d605" }}How your request composes with the agent
Section titled “How your request composes with the agent”input— delivered to the run. If the agent declares exactly one named text input, your text binds to it; if it declares none, your text becomes the run conversation’s opening user message (visible context for every step). Agents with two or more named inputs — or a single non-text input — cannot take freeform input (400 agent_inputs_unmappable); usePOST /v1/agents/runswith named inputs.instructions— optional; appended after the agent’s own system prompt.metadata— echoed back, merged with the run linkage keys.- Everything pinned by the agent’s stored configuration (
tools, non-"auto"tool_choice, sampling parameters,conversation,previous_response_id,background) is rejected with400 unsupported_parameternaming the field — nothing is silently dropped.
Stream the run live
Section titled “Stream the run live”Set stream: true to watch the run as it progresses. The run’s
activity streams as standard Responses output items — assistant text
as live response.output_text.delta events, plus reasoning summaries
and tool-call items as each step executes:
curl -N -X POST https://api.kindo.ai/v1/responses \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $KINDO_API_KEY" \ -d '{ "model": "agent/8e051857-978c-4207-8916-28a3d4c4d605", "input": "Triage INC-4821 and propose a remediation plan.", "stream": true }'event: response.createdevent: response.in_progressevent: response.output_item.added ← message / reasoning / tool-callevent: response.output_text.delta items, streamed live as eachevent: response.output_text.done step of the run executesevent: response.output_item.done...event: response.completed ← carries the full final responsedata: [DONE]Notes on stream semantics:
- Steps stream live, at item granularity. Assistant text arrives
as
response.output_text.deltaevents; reasoning summaries stream asresponse.reasoning_summary_text.delta; tool activity appears as typed items (mcp_call,kindo_call,shell_call,web_search_call) with their own argument-delta events. See Streaming for the event vocabulary. - A step that already finished before you connected is replayed as
completed items (
response.output_item.added+response.output_item.donepairs) rather than re-streamed token-by-token. - A failed run ends with
response.failed; a run cancelled from the Kindo Terminal ends with anerrorevent (code: "run_cancelled"). Every terminal path is followed bydata: [DONE]. - Streams are capped at 30 minutes (
error/code: "stream_timeout"). The run itself keeps executing — switch to polling below. - If you disconnect, nothing is lost: the run continues server-side
and remains pollable. To re-attach to the stream, reconnect with
GET /v1/responses/{id}?stream=true— agent-run responses replay from the beginning and then continue live (see Streaming → resuming).
Poll to completion (non-streaming)
Section titled “Poll to completion (non-streaming)”Without stream: true, take the id from the immediate response and
poll GET /v1/responses/{id} until the status is terminal:
import time
response = client.responses.create( model="agent/8e051857-978c-4207-8916-28a3d4c4d605", input="Triage INC-4821 and propose a remediation plan.",)
while response.status == "in_progress": time.sleep(3) response = client.responses.retrieve(response.id)
print(response.status) # completed | failed | cancelledprint(response.output_text) # the run's final answercurl https://api.kindo.ai/v1/responses/resp_run_04f0faa6-2e66-4f5a-b49f-6a28daa58d9b \ -H "Authorization: Bearer $KINDO_API_KEY"Statuses: in_progress → completed, failed, or cancelled.
Read the output
Section titled “Read the output”The response carries the run’s activity as standard Responses output
items — populated incrementally while the run is in_progress, and
complete on a terminal status:
output— the run’s assistant turns as output items:messageitems withoutput_textcontent,reasoningsummaries, and tool activity (mcp_call,kindo_call,shell_call,web_search_call) where present.output_text— the concatenated final answer text.usage— token usage aggregated across the run.metadata.kindo_run_id/metadata.kindo_agent_id— run linkage. The run ID also works withGET /v1/runs/{runId}if you already integrate with the agents API.conversation.id— the run’s conversation. Read the full step-by-step transcript withGET /v1/conversations/{id}/items.
Current limitations
Section titled “Current limitations”Stated plainly, so you can design around them today:
- No request
toolson agent models. The agent’s tool set is pinned by its configuration; additive request tools are planned. - No
conversation/previous_response_idon agent models, and agent-run response IDs (resp_run_*) are not chainable viaprevious_response_id(you get404 previous_response_not_found). Conversation continuity for agent runs — follow-up turns to the same run conversation — is upcoming. - Version pinning is not available yet.
agent/<id>@<version>returns400 agent_version_pinning_unsupported; invocations always run the agent’s latest configuration. - Freeform
inputbinds to at most one text input. An agent that declares two or more named inputs — or a single non-text input — returns400 agent_inputs_unmappable; run it withPOST /v1/agents/runsand named inputs instead.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
400 | model_not_found | Unknown, malformed, or inaccessible agent ID — indistinguishable from an unknown model on purpose. |
400 | agent_version_pinning_unsupported | agent/<id>@<version> — drop the version suffix. |
400 | agent_inputs_unmappable | The agent declares 2+ named inputs, or a single non-text input — use POST /v1/agents/runs. |
400 | unsupported_parameter | A request field conflicts with the agent’s pinned configuration; the message names the field. |
404 | previous_response_not_found | You passed a resp_run_* ID (or any non-stored response ID) as previous_response_id. |
404 | not_found | GET /v1/responses/resp_run_* for a run that doesn’t exist or that you cannot access. |
All errors use the standard Responses error envelope.
See also
Section titled “See also”- Responses API quickstart — point your SDK at Kindo.
- Request shape —
agent/<agent-id>in the field reference. - Model catalog —
discover agents with
include_agents=true. - Agents API — the control-plane surface (list agents, named-input runs, run results).