Skip to content

API reference

Store, recall, and the keys for both.

Two endpoints do the work — /memories and /recall — and a third issues the key for them. A key lasts seven days and holds twenty chunks, searched alongside a demonstration corpus so recall has something to rank on the first call. Regional pinning and customer-managed keys are not exposed yet; responses carry "sandbox": true until they are.

Quickstart

Take a key, store a chunk, ask a question. Paste the whole block into a terminal.

KEY=$(curl -s -X POST $ITAN_HOST/api/keys | jq -r .key)

curl -s -X POST $ITAN_HOST/api/memories \
  -H "Authorization: Bearer $KEY" \
  -d '{"source":"notes.md","text":"Rate limit is 600 rpm per key."}'

curl -s -X POST $ITAN_HOST/api/recall \
  -H "Authorization: Bearer $KEY" \
  -d '{"query":"what is the rate limit?","max_tokens":2000}' \
  | jq '{sufficient, tokens_estimated, prompt}'

Issue a key

POST /api/keys

Returns an HMAC-signed sandbox key. Takes no body, and nothing is recorded — the signature is what gets verified on later requests. Five per minute per address.

{
  "key": "itan_sb_1785404658352.gSYI...zQ.i8Xk...",
  "expires_at": "2026-08-06T09:14:22.104Z",
  "scope": "memories:write recall:read",
  "sandbox": true
}

Store a chunk

POST /api/memories

Stores one chunk under the calling key. It is queryable on the next recall — no indexing delay to wait out. GET the same path to list what the key holds.

textstringrequired
The content to store. 2,000 characters or fewer in the sandbox.
sourcestring
Where it came from. Returned on every chunk that cites it. Defaults to "untitled".
{
  "id": "m_i8Xk_1",
  "source": "notes.md",
  "chunk": 1,
  "queryable": true,
  "stored_for_key": 1,
  "sandbox": true
}

Delete chunks

DELETE /api/memories

Removes one chunk when you pass ?id=, or everything the key holds when you do not. The response is the count that no longer exists — the next recall cannot return any of it.

{
  "deleted": 3,
  "scope": "key",
  "remaining": 0,
  "sandbox": true
}

Recall context

POST /api/recall

Runs the strategy you name over the demonstration corpus and your stored chunks, then returns them ranked and cited plus a prompt-ready string. Sixty per minute.

querystringrequired
The question. Embedded the same way your stored text was.
top_kinteger
How many chunks to return, 1–20. Defaults to 8.
max_tokensinteger
Budget for the whole returned prompt, 64–32000. Returns as many ranked chunks as fit and no more. Overrides top_k, which becomes the ceiling on the pool it packs from.
as_ofstring
ISO date. Runs the query against the corpus as it stood that day — anything written later is invisible, including your own chunks.
strategystring
One of semantic, hybrid, recency, mmr, graph, rerank. Defaults to hybrid.
{
  "chunks": [
    {
      "text": "Overage billing shall not exceed 115%...",
      "source": "acme_msa_2024.pdf",
      "chunk": 41,
      "score": 1,
      "written_at": "2024-03-01"
    }
  ],
  "prompt": "Answer using only the context below...",
  "sufficient": true,
  "sufficiency_reason": "3 of 3 query terms appear in the returned context.",
  "strategy": "hybrid",
  "tokens_estimated": 397,
  "returned": 8,
  "latency_ms": 3,
  "sandbox": true
}

prompt is the field to use. It carries the instruction, the question, and the numbered chunks, so it drops straight into a system prompt. What each strategy does.

Ask for a budget, not a count

You know how much room the context has; you do not know how many chunks fill it. Send max_tokens and recall packs ranked chunks until the assembled prompt would exceed it, then stops. tokens_estimated is what it spent — an estimate at four characters per token, not a tokeniser reading, and it errs high.

Know when the answer is not in there

Ranked retrieval always returns its best chunks, even when the best is merely the least bad — which is where most grounded hallucination starts. sufficient is false when the returned context does not cover the question, so you can branch instead of finding out from the model. sufficiency_reason names what was missing. It is a lexical coverage test: it catches a question the corpus has nothing to say about, and will not catch a paraphrase that shares no vocabulary with its own answer.

Ask what you knew in March

as_of runs the query against the corpus as it stood on a past date. Anything written later is invisible — not down-ranked, absent — and the ranking statistics are rebuilt over what remains. Recency decays from that date rather than from today.

Errors

Every failure returns a JSON body with a stable error code and a human-readable message. Match on the code, print the message.

401
missing_authorization
No Authorization header. Send Bearer <key>.
401
invalid_key
Signature did not verify. The key was altered or was not issued by us.
401
key_expired
Sandbox keys last seven days. Request another.
400
invalid_json
The body was not parseable JSON.
422
invalid_text
text was missing, empty, or over 2,000 characters.
422
invalid_query
query was missing or empty.
422
invalid_top_k
top_k was not an integer between 1 and 20.
422
invalid_max_tokens
max_tokens was not an integer between 64 and 32000.
422
invalid_as_of
as_of was not an ISO 8601 date.
422
invalid_strategy
strategy was not one of the six.
409
quota_exceeded
A sandbox key holds 20 chunks. Delete some, or request another key.
404
not_found
The id given to DELETE is not a chunk this key holds.
429
rate_limited
60 recalls and 30 writes per minute. Retry-After is set.

Start with a key.

A key is issued instantly and lasts seven days. Store a chunk, recall it with any of the six strategies, delete it and get the count back. No sign-up, no card, no call.

Read the API reference