Every Kijito operation is a plain REST call. The fastest way in is an MCP client, but if you are building directly, this is the surface - bearer auth, JSON in, JSON out.
All endpoints live under https://api.kijito.ai/api. Every route is also served, with identical behavior, under a version prefix: https://api.kijito.ai/api/v1. Integrations should call the /api/v1 paths - a future breaking change would ship under a new prefix (/api/v2) while /api/v1 keeps its contract.
Changes within a version are additive: new optional fields, new routes, new arguments. A retired route returns 410 Gone naming its replacement. Kijito is currently in public beta (API version 0.1.0); the running version is always available at GET /api/version.
Sign in once to get an access token, then send it as a Bearer header on every call. The access token is a JWT valid for one hour; use the longer-lived refresh token to mint a new one.
For unattended or long-running agents, mint a standalone API key: a kjt_-prefixed bearer token, scoped to a least-privilege subset of your own data (memory.read, memory.write, memory.curate, memory.dream) and optionally set to expire. Send it as the Bearer header exactly like an access token - it never needs refreshing. Keys are minted from a full login session (a scoped key cannot mint another), and the secret is shown exactly once at creation.
The same key works as the Bearer header on the MCP server. Interactive clients can use the MCP connector's OAuth sign-in instead (see the Quickstart); because every OAuth refresh rotates the token, several unattended processes sharing one sign-in will invalidate each other's sessions, so give each unattended agent its own key.
# Sign in and capture the access token from the response body.
TOKEN=$(curl -s https://api.kijito.ai/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}' \
| jq -r .access_token)The token endpoints:
| Method & path | Body → returns |
|---|---|
POST /api/v1/auth/login | {email, password} → {access_token, refresh_token, user}. Rate-limited per email. |
POST /api/v1/auth/refresh | {refresh_token} (or the refresh cookie) → {access_token, refresh_token}. The refresh token is rotated: it is single-use, and the response carries its replacement in the same field login returns - store the new one, the presented one stops working immediately. Reusing a spent refresh token signs the whole account out (the session family is revoked), so never replay an old one. A rotated token inherits the original sign-in's expiry; rotating does not extend a session. |
GET /api/v1/auth/me | The current authenticated user. |
POST /api/v1/auth/tokens | Mint a scoped API key. {name, scopes, expires_in_days?} → {id, name, scopes, token, prefix, expires_at} - token is the kjt_ secret, returned once. Requires a full login session. |
GET /api/v1/auth/tokens | List your API keys (prefix, scopes, last used, expiry) - never the secret. |
DELETE /api/v1/auth/tokens/{id} | Revoke an API key by id. |
# Mint a read+write key that expires in 90 days. Save "token" now - it is shown only once.
curl https://api.kijito.ai/api/v1/auth/tokens \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "ci-agent", "scopes": ["memory.read", "memory.write"], "expires_in_days": 90}'
# Then use the returned kjt_ token as the bearer on every call - no refresh needed.Most write and recall handlers return {"result": <text>} - a rendered, agent-ready summary rather than raw rows. Data endpoints for the web UI (export, stats) return structured JSON.
| Method & path | Purpose & body |
|---|---|
POST /api/v1/remember | Store a memory. {content} required; optional importance, persona, project, scope, memory_type, basis, confidence. 400 if content is missing or over 65,536 bytes. |
POST /api/v1/remember/batch | Store many at once. {memories: [ ... ]} → {result, count}. All are validated before any is written. |
POST /api/v1/recall | Associative recall by meaning. {query} required; optional limit, full, scope, project, min_confidence, explain. 400 if no query. |
GET /api/v1/memory/{id} | Full content of one memory by id. |
POST /api/v1/memory/{id}/correct | Correct a memory. {content} - fades the original and writes a linked, superseding version (history preserved). |
PATCH /api/v1/memory/{id} | Update metadata or content in place (e.g. a living "current status" note): content, importance, memory_type, permanent. |
POST /api/v1/fade | Soft-delete: drop a memory's importance to the fade floor so it leaves recall. {id}. Preferred over hard deletion. |
DELETE /api/v1/memory/{id} | Permanently delete one of your memories. |
POST /api/v1/relate | Author a typed edge between two memories. {from_id, to_id, rel_type} required; optional weight, reason. |
POST /api/v1/confirm | Corroborate a memory with an independent source (raises its confidence). |
POST /api/v1/search | Structured, non-semantic search by memory_type, persona, status, min_importance, and date range. |
GET /api/v1/recent?hours=24 | Memories stored in the last N hours (truncated previews). |
curl https://api.kijito.ai/api/v1/remember \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "We chose aqua as the primary accent.", "importance": 0.7}'curl https://api.kijito.ai/api/v1/recall \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "what did we decide about color?", "limit": 5}'# Supersede memory 1423 without losing its history.
curl https://api.kijito.ai/api/v1/memory/1423/correct \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "We switched the primary accent from aqua to amber."}'Goals are tracked, decay-exempt intentions an agent carries across sessions.
| Method & path | Purpose & body |
|---|---|
POST /api/v1/goals | Create a goal. {title} required; optional description, priority, scope, project. |
GET /api/v1/goals | List active goals. |
POST /api/v1/goals/{id}/complete | Mark a goal complete. |
Durable persona-to-persona messaging within your account. A message is kept after it is read, not consumed.
| Method & path | Purpose & body |
|---|---|
POST /api/v1/send | Send a message to another persona. {to, content} → {result: {id, to}}. 403 if the from persona is not one you own. |
GET /api/v1/inbox?persona=NAME | Read a persona's inbox. 403 on a persona you do not own. |
GET /api/v1/presence | The roster of personas active in this account right now, each marked active or idle. Read-only and safe to poll; empty shortly after a restart. |
GET /api/v1/reachability?persona=NAME | List a persona's wake channels. 403 on a persona you do not own. |
POST /api/v1/reachability | Manage a persona's wake channels - there is no web UI for this. {action, persona, ...} where action is register (with channel_type and address), verify or disable (with channel_id). |
# river leaves a durable note for the omniview agent.
curl https://api.kijito.ai/api/v1/send \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "omniview", "content": "Deploy is green - pick up the frontend pass."}'| Method & path | Returns |
|---|---|
GET /api/v1/stats | Graph statistics for your account. |
GET /api/v1/dashboard | Summary counts: active/total memories, edges, themes, last dream, session count, personas. |
GET /api/v1/usage | Your plan's limits and current usage (memory cap, graph footprint, write rate). |
GET /api/health (public) | {status, embedder_ready, dreaming}. A slim public response - no memory counts, process memory, or internal telemetry (those are on the authenticated admin health endpoint). No auth required. |
GET /api/version (public) | {version, commit, uptime_seconds, schema_version}. No auth required. |
Your data is yours - pull the whole graph out at any time.
| Method & path | Returns |
|---|---|
GET /api/v1/export | Your entire graph as JSON (including your consent log). |
GET /api/v1/export/gexf | GEXF for graph tools such as Gephi. |
curl https://api.kijito.ai/api/v1/export \
-H "Authorization: Bearer $TOKEN" -o kijito-export.jsonErrors return a JSON body of the shape {error, code} with a matching HTTP status. Treat an unrecognized code as a generic failure for its status. Common ones:
| Status | Meaning |
|---|---|
400 | Bad request - a required field is missing or a limit (e.g. content size) is exceeded. |
401 | Missing, invalid, or expired bearer token. Refresh and retry. |
403 | Authenticated, but not permitted - e.g. acting as a persona you do not own. |
409 | Conflict - for example a dreaming pass is already in progress. |
410 | Gone - the route was retired; the message names its replacement. |
429 | Rate or capacity limit hit (write rate, memory cap). Back off and retry. |
Through an MCP client, each of these endpoints is a tool with the same name - kijito_remember, kijito_recall, kijito_correct, kijito_dream, and so on - dispatched over the same graph with the same per-account isolation. See the Quickstart for connecting a client.