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.
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:
- Interactive API reference, every endpoint, browsable
- OpenAPI schema, machine-readable
- Postman collection, generated from the same schema
- llms.txt and llms-full.txt, for coding agents
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