Build with the AI

Memories

Save and manage the durable facts the AI remembers about you.

A memory is an explicitly-saved fact about you — “prefers TypeScript over JavaScript”, “timezone is CET”, “deploys on Fridays”. Unlike a conversation turn, a memory is user-global: it is not tied to any single chat, guild, or persona, and it follows you across every AI surface on your account. The /api/v1/memories endpoints let you read, create and delete these facts programmatically, the same store the AI itself writes to when it decides something is worth remembering.

Memories are scoped to the owner of the API key, not to a conversation. A fact you POST here is visible to a later GET or DELETE from any key the same owner holds, and is injected into that owner’s AI context everywhere.

How memories work

Three properties are worth internalizing before you write against this API:

To steer how the AI reasons rather than what it knows about you, attach your own persona to a request — personas and memories are independent and compose freely.

Scopes

Each memory operation requires the matching scope on your API key:

OperationMethodScope
List memoriesGETmemories:read
Save a memoryPOSTmemories:write
Delete a memoryDELETEmemories:write

A request missing the required scope returns 403 insufficient_scope with the needed scope echoed in error.required_scope. Grant scopes when you mint a key in the Developer console; see Scopes and Authentication.

The memory object

Every endpoint that returns a memory serializes it with exactly these fields:

FieldTypeDescription
idintegerStable identifier for the fact. Use it to delete the memory.
contentstringThe stored fact, trimmed and truncated to the configured maximum length.
created_atstring · nullISO-8601 UTC instant the fact was saved (e.g. 2026-07-14T18:32:05Z). May be null if the timestamp is unavailable.

Responses use the native Krallo envelope: successful bodies are wrapped as { "data": …, "meta": { "request_id": … } }. Errors are { "error": { "code", "message", … }, "meta": … }. See Errors for the full contract.

List memories

GET/api/v1/memories

Returns your saved facts as a JSON array, newest first (by creation time, ties broken by descending id). Requires memories:read.

Query parameters

NameTypeRequiredDescription
limit integer No Maximum number of facts to return. Defaults to 50. Clamped to the range 1–200; a missing or non-numeric value falls back to the default.

Request

cURL
curl "https://exe.krallo.com/api/v1/memories?limit=10" \
  -H "Authorization: Bearer krallo_live_..."

Response

{
  "data": [
    {
      "id": 8241,
      "content": "Prefers TypeScript and pnpm; deploys are gated behind CI.",
      "created_at": "2026-07-14T18:32:05Z"
    },
    {
      "id": 8109,
      "content": "Primary timezone is CET (Europe/Berlin).",
      "created_at": "2026-07-11T09:14:47Z"
    }
  ],
  "meta": { "request_id": "5f3a91c0-b2d4-4e16-9a58-c07d2f4b8e31" }
}

An owner who has never saved a fact receives "data": [] with a 200 status.

Save a memory

POST/api/v1/memories

Saves a single user-global fact and returns it. Requires memories:write. Responds 201 Created on success.

Body parameters

NameTypeRequiredDescription
content string Yes The fact to remember. Must be non-blank. Leading/trailing whitespace is trimmed, then the text is truncated to AI_MEMORY_FACT_MAX_CHARS characters (default 500). A missing or blank value returns 400 invalid_request.

Request

cURL
curl https://exe.krallo.com/api/v1/memories \
  -H "Authorization: Bearer krallo_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "content": "Prefers TypeScript and pnpm; deploys are gated behind CI." }'

Response

{
  "data": {
    "id": 8241,
    "content": "Prefers TypeScript and pnpm; deploys are gated behind CI.",
    "created_at": "2026-07-14T18:32:05Z"
  },
  "meta": { "request_id": "9c1e77aa-04f3-4b8d-a25c-6e19d0b74f82" }
}

In the rare case the row cannot be read back immediately after insertion, the response still confirms the write with a minimal body — { "id": 8241, "saved": true } — instead of the full object. The fact is saved either way; fetch it later with List memories.

Saving with memory off

If memory is disabled for the account, a save is refused with 409 memory_disabled and nothing is stored. This is checked before the call is billed, and re-checked at write time to close the race where the switch is toggled off mid-request:

{
  "error": {
    "code": "memory_disabled",
    "message": "Memory is disabled for this account. Enable it before saving facts."
  },
  "meta": { "request_id": "2b40de19-f7a6-4c53-8d90-1e4b7a2c5f68" }
}

Re-enable memory in your account’s AI privacy settings, then retry the save.

Delete a memory

DELETE/api/v1/memories/{id}

Permanently deletes one saved fact by id. Requires memories:write. Deletion is owner-scoped: you can only delete your own facts, and an id that does not exist (or belongs to another owner) returns 404 not_found rather than revealing anything about it.

Path parameters

NameTypeRequiredDescription
id integer Yes The id of the memory to delete, from a list or save response. A non-numeric path segment returns 404 not_found.

Request

cURL
curl -X DELETE https://exe.krallo.com/api/v1/memories/8241 \
  -H "Authorization: Bearer krallo_live_..."

Response

{
  "data": { "id": 8241, "deleted": true },
  "meta": { "request_id": "e70b2c88-15d9-4a37-b642-90c1f5e8a3d4" }
}

Memories are immutable — there is no update. A PATCH or PUT against /api/v1/memories/{id} returns 405 method_not_allowed, and there is no endpoint to fetch a single memory. To change a fact, delete it and POST a new one.

Billing & rate limits

Every memory call — list, save, and delete — is a flat metered request. Calls first draw down your app’s free daily allowance; once that is exhausted, and if wallet billing is enabled, each call debits a small, fixed number of credit units from the owner’s balance. If the wallet cannot cover a billable call, the request returns 402 insufficient_credits with required_units and balance in the error body, and nothing is changed. Refused or errored calls are refunded and do not burn quota. See Billing for the full model.

Requests are rate-limited per key by your app’s tier. Every authenticated response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers (pre-auth 401/403 responses do not); exceeding the limit returns 429 with a Retry-After header. See Rate limits.

Errors

Memory endpoints can return the following errors, in addition to the standard bearer-auth failures:

StatusCodeWhen
400invalid_requestcontent is missing or blank on a save.
401unauthorizedNo bearer token was supplied.
401invalid_token · token_revoked · token_expiredThe key is unknown, revoked, or past its expiry.
402insufficient_creditsOver the free quota and the wallet cannot cover the billable call.
403insufficient_scopeThe key lacks memories:read (read) or memories:write (save/delete).
403app_disabled · owner_suspendedThe owning app is disabled, or the account is suspended.
404not_foundDelete of an unknown or non-owned id, a non-numeric id, or the developer platform is disabled.
405method_not_allowedAn unsupported method, e.g. PATCH/PUT on a memory, or GET on a single-memory path.
409memory_disabledMemory is turned off for the account; saving is refused.
429rate_limitedThe per-key rate limit was exceeded.
500internal_errorAn unexpected server-side failure; the call is refunded.

Apart from the 429 — written by the shared rate limiter as a bare { "error": "rate_limited", "hint", "retryAfterSeconds" } body — all errors share the native envelope shape. For status semantics and retry guidance, see Errors. Related reading: Personas, Chat completions, and Authentication.