surface

Quickstart.

Get an API key, make an authenticated call, discover a node type and execute a run. Roughly fifteen minutes, no conversation with anyone required.

Written for
Developers calling Kaitoi from their own code for the first time.
You need
A Kaitoi Studio account; curl or any HTTP client

Kaitoi Core is the programmable platform underneath Kaitoi Studio. The canvas is one client of it. This page gets you to a working authenticated call, then to a real run.

Every endpoint lives under one base URL:

https://api.studio.kaitoi.io/api/v1

1. Get an API key

Keys are issued from your Kaitoi Studio account, under Settings → Developer → API Keys → New API Key.

Keys are scoped. Grant only what the integration needs:

Scope Allows
projects:read Read projects
projects:write Create and update projects
graphs:read Read project graphs
node_types:read Discover node types and their schemas
runs:execute Create and manage runs
files:read, files:write Read and upload files
templates:read, templates:run Read and run template endpoints
account_credits:read Read the account credit balance

There are two kinds of key, and the difference is not cosmetic:

  • Backend service keys are the default. They are bearer secrets, for your own backend, CLI tools, desktop apps, workers and CI jobs. Do not ship one in browser JavaScript.
  • Browser app keys are for calling Kaitoi directly from frontend JavaScript. They must be attached to a Developer App with an explicit list of allowed origins. The origin check is a containment measure, not a secret: anything in a browser is visible to the person using it, so keep these read-only or narrowly scoped.

For most production web apps the right shape is the boring one. Your frontend calls your backend, and your backend calls Kaitoi with a service key.

Keep the key in an environment variable for the rest of this page:

export KAITOI_API_KEY="your key here"

2. Confirm the key works

The cheapest authenticated call reads your credit balance. It needs account_credits:read.

curl -s https://api.studio.kaitoi.io/api/v1/account/credits \
  -H "Authorization: Bearer $KAITOI_API_KEY"

A working key returns your balance in three forms: credits, exact microcredits, and dollars.

{
  "balanceCents": 1250,
  "balanceMicrocredits": "1250110000",
  "balanceDollars": 12.5
}

Use balanceMicrocredits for anything that has to reconcile exactly. balanceCents is rounded and will not always agree with it to the last unit.

If something is wrong, you will get a 401 with a body that says which problem it is. Missing header:

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing Authorization header. Send 'Authorization: Bearer <api_key>'.",
    "details": {}
  }
}

Bad key:

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "API key is invalid, expired, or revoked.",
    "details": {}
  }
}

Every error in the API uses that { "error": { "code", "message", "details" } } shape. Branch on code, not on the message text.

3. Find something to run

Do not hard-code node types. The catalogue differs per account and changes over time. Search it:

curl -s "https://api.studio.kaitoi.io/api/v1/node-types?search=image&limit=5" \
  -H "Authorization: Bearer $KAITOI_API_KEY"

Pick a type from the results, then read its schema to learn its input pins:

curl -s "https://api.studio.kaitoi.io/api/v1/node-types/$NODE_TYPE" \
  -H "Authorization: Bearer $KAITOI_API_KEY"

You need the exact input names from that response for the next step.

4. Run it

You do not need to save a project first. Send the graph inline:

curl -s -X POST https://api.studio.kaitoi.io/api/v1/runs \
  -H "Authorization: Bearer $KAITOI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "graph": {
      "nodes": [
        {
          "id": "a",
          "type": "'"$NODE_TYPE"'",
          "inputs": {
            "<input name from step 3>": { "type": "string", "value": "<value>" }
          }
        }
      ]
    },
    "targetNodeIds": ["a"]
  }'

Four things about that request are worth not skipping.

Each input is a typed pin object, { "type": ..., "value": ... }, not a bare value. A bare value is rejected with INVALID_INPUT_VALUE before anything runs. The types are string, number, boolean, json, file and null.

targetNodeIds is required for an inline graph. There is no saved project to supply a default target.

Idempotency-Key should be on every run you create. If the connection drops after the server accepted the run, a retry without the key starts a second run and charges you twice.

The response is 202 Accepted with a run record, not a result. Runs are asynchronous.

{
  "id": "run_...",
  "sourceType": "inline_graph",
  "status": "accepted",
  "targetNodeIds": ["a"],
  "createdAt": "..."
}

5. Wait for it

Poll the run until it reaches a terminal status:

curl -s "https://api.studio.kaitoi.io/api/v1/runs/$RUN_ID" \
  -H "Authorization: Bearer $KAITOI_API_KEY"

status moves through accepted, queued and running to one of succeeded, failed or canceled. On success, outputs holds the result and creditsUsed holds what it cost.

Outputs come back in the same typed shape the inputs use:

{
  "status": "succeeded",
  "creditsUsed": 0,
  "executionTimeMs": 439,
  "outputs": {
    "outputText": { "type": "string", "value": "Kaitoi quickstart verification" }
  }
}

If you want progress rather than a result, stream the run's events instead:

curl -N "https://api.studio.kaitoi.io/api/v1/runs/$RUN_ID/events/stream" \
  -H "Authorization: Bearer $KAITOI_API_KEY"

That is Server-Sent Events. The event id is an opaque cursor you can send back as Last-Event-ID to resume after a dropped connection.

Rate limits

Requests are limited per client IP before authentication and per API key after it. A 429 RATE_LIMITED response carries a Retry-After header. Honour it.

In production the limiter is shared across backend instances and fails closed, so a 503 RATE_LIMIT_UNAVAILABLE means the limiter itself could not be reached, not that you did anything wrong. Back off and retry.

Where the full reference lives

This page is a starting point, not the contract. The contract is generated from the running API, so it cannot drift from it:

Current limitations

  • Runs are observed by polling or SSE. There is no run-level webhook yet.
  • List cursors are opaque. Never parse or construct one.

Last reviewed against Kaitoi on 16 September 2026. View this page as Markdown

Type at least two characters.