surface

Quickstart.

Get a scoped REST key, discover a node schema, submit one inline graph run, follow its status and events, and recover uncertain submissions safely.

Written for
Developers calling Kaitoi from their own code for the first time.
You need
Any plan for REST API access and API keys; A Kaitoi Studio account; curl or any HTTP client
Interactive API reference Explore endpoints, request schemas and responses. Opens in a new tab

Run the free Text node through the public REST API, then read its output. You need a Kaitoi account, curl, jq and Python 3. This example makes no model or media-provider call.

Create a key

In Studio, open Settings → Developer → API Keys → New API Key. Choose a Backend service key with node_types:read, runs:execute and runs:read. Keep it on your trusted computer or backend, never in browser code.

export KAITOI_API_KEY='paste-your-key'
export KAITOI_API_BASE='https://api.studio.kaitoi.io/api/v1'

See authentication and the complete scope list for browser keys and other operations. Graph document writes require both projects:write and graphs:write.

Discover the node

curl --fail-with-body -sS \
  -H "Authorization: Bearer $KAITOI_API_KEY" \
  "$KAITOI_API_BASE/node-types/builtin/utils/text"

The input is inputText; the output is outputText. REST detail lists each pin's name, type, label, default and exposed status. Inspect full controls, requirements and help in Studio.

Submit one logical run

Save the body and key so a lost response can be recovered without new work.

Retain the request and key, then follow the returned run ID.

Submit the free Text node with a typed inputText value and a stable Idempotency-Key. A 202 response returns a run ID. Poll that ID until terminal, then read outputText. If the response is lost, resend the identical body with the same key and authenticated API key. A completed replay returns the original 202 and ID for seven days; IDEMPOTENCY_REQUEST_IN_PROGRESS means wait and resend. REST has no run list or search to recover a lost ID without a key.

cat > kaitoi-text-run.json <<'JSON'
{
  "graph": {
    "nodes": [{
      "id": "text",
      "type": "builtin/utils/text",
      "inputs": {"inputText": {"type": "string", "value": "Hello from Kaitoi"}}
    }],
    "connections": []
  },
  "targetNodeIds": ["text"]
}
JSON

KAITOI_REQUEST_KEY="$(python3 -c 'import uuid; print(uuid.uuid4())')"
printf '%s\n' "$KAITOI_REQUEST_KEY" > kaitoi-text-run.key

curl --fail-with-body -sS \
  -H "Authorization: Bearer $KAITOI_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $KAITOI_REQUEST_KEY" \
  --data-binary @kaitoi-text-run.json \
  "$KAITOI_API_BASE/runs" > kaitoi-text-accepted.json

RUN_ID="$(jq -er '.id' kaitoi-text-accepted.json)"
printf '%s\n' "$RUN_ID"

Inputs use nested transport values: {"type":"string","value":"..."}, not bare strings. Inline graphs require explicit targetNodeIds.

Read the result

curl --fail-with-body -sS \
  -H "Authorization: Bearer $KAITOI_API_KEY" \
  "$KAITOI_API_BASE/runs/$RUN_ID" | jq '{id,status,outputs,error}'

Repeat that read with a short delay while status is accepted, queued or running. Success is succeeded; failed and canceled are terminal too. On success, outputs.outputText contains the string transport value Hello from Kaitoi. For a single target, output keys are pin names; multiple targets use nodeId.pinName. File outputs have type:"file", fileId, content metadata and temporary download URLs.

Recover a lost response

Read the saved key from kaitoi-text-run.key and repeat the submission with the unchanged JSON body and same API key. A completed replay returns the original 202 and run ID for seven days. For IDEMPOTENCY_REQUEST_IN_PROGRESS, wait and resend. Without a key, there is no REST run list or search to recover a lost ID. Replaying does not restart failed work.

Observe, retry and expand

Runs and events covers polling, cancellation and SSE. Resume a stream with its SSE id: line as Last-Event-ID, not the JSON data.id.

Errors and retries lists structured errors. Documented route errors use {error:{code,message,details,requestId?}}; unknown routes and unsupported methods may use FastAPI's detail shape. For rate limiting, honor Retry-After, or error.details.retryAfterSeconds in browser code. A 403 with details.capability:"public_rest_api" means the account has REST access disabled.

Projects explains persistent workflows and version guards. Files explains uploads and temporary downloads. Model and media-provider nodes may spend credits; choose them deliberately after the free example works.

Last reviewed against Kaitoi on 26 October 2026. View this page as Markdown

Type at least two characters.