Skip to content

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.

  1. A Kindo API key — see Authentication.

  2. 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.

import os
from 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_progress
Terminal window
curl -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"
}
}
  • input — delivered to the run. If the agent declares exactly one named 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 cannot take freeform input — use POST /v1/agents/runs with 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 with 400 unsupported_parameter naming the field — nothing is silently dropped.

Set stream: true to watch the run as it progresses. Each completed step of the run arrives as a finished output item:

Terminal window
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.created
event: response.in_progress
event: response.output_item.added ← one pair per completed step item
event: response.output_item.done (message text, tool calls, ...)
event: response.completed ← carries the full final response
data: [DONE]

Notes on stream semantics:

  • Items arrive whole, per completed step — you see each step’s output as the run advances, not token-by-token deltas. (Token-level streaming for agent runs is upcoming.)
  • A failed run ends with response.failed; a run cancelled from the Kindo Terminal ends with an error event (code: "run_cancelled"). Every terminal path is followed by data: [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.

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 | cancelled
print(response.output_text) # the run's final answer
Terminal window
curl https://api.kindo.ai/v1/responses/resp_run_04f0faa6-2e66-4f5a-b49f-6a28daa58d9b \
-H "Authorization: Bearer $KINDO_API_KEY"

Statuses: in_progresscompleted, failed, or cancelled.

On a terminal status the response carries the run’s final output as standard Responses output items:

  • output — the final turn’s items (an assistant message with output_text content; tool calls of the final turn where present).
  • output_text — the concatenated final answer text.
  • usage — token usage of the final turn.
  • metadata.kindo_run_id / metadata.kindo_agent_id — run linkage. The run ID also works with GET /v1/runs/{runId} if you already integrate with the agents API.
  • conversation.id — the run’s conversation. Read the full step-by-step transcript with GET /v1/conversations/{id}/items.

Stated plainly, so you can design around them today:

  • No request tools on agent models. The agent’s tool set is pinned by its configuration; additive request tools are planned.
  • No conversation / previous_response_id on agent models, and agent-run response IDs (resp_run_*) are not chainable via previous_response_id (you get 404 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> returns 400 agent_version_pinning_unsupported; invocations always run the agent’s latest configuration.
  • Per-step tool-call detail in the stream is upcoming. Today the stream is step-granular (whole items per completed step); the final response carries the final turn’s items. The full transcript is always available via the run’s conversation items.
  • Trigger-driven agents can’t be invoked directly (400 agent_not_invocable) — they run when their trigger fires.
StatusCodeMeaning
400model_not_foundUnknown, malformed, or inaccessible agent ID — indistinguishable from an unknown model on purpose.
400agent_version_pinning_unsupportedagent/<id>@<version> — drop the version suffix.
400agent_not_invocableThe agent has triggers and cannot be invoked directly.
400agent_inputs_unmappableThe agent declares 2+ named inputs — use POST /v1/agents/runs.
400unsupported_parameterA request field conflicts with the agent’s pinned configuration; the message names the field.
404previous_response_not_foundYou passed a resp_run_* ID (or any non-stored response ID) as previous_response_id.
404not_foundGET /v1/responses/resp_run_* for a run that doesn’t exist or that you cannot access.

All errors use the standard Responses error envelope.