Open app

API reference.

Every endpoint, request field, and error code. Plain HTTPS against api.leapmemory.com.

Authentication
One header on every request.
HTTP
Authorization: Bearer lm_sk_your_key_here

Keys are created in the dashboard under API keys. A missing, malformed, or revoked key returns 401 auth_required. Keep keys server-side; never ship one in a browser or mobile app.


Response envelope
Every response, success or error, uses one shape.
JSON
# success
{ "success": true,  "http_status": 200, "code": "ok",        "data": { ... } }

# error
{ "success": false, "http_status": 404, "code": "not_found", "message": "tenant not found" }

Branch on success, then read data or message. The code string is stable and safe to match on; message is human-readable and may change.


Key roles & scopes
What a key is allowed to do, and which tenants it can reach.
RoleCan call
adminEverything: tenant management and all memory operations.
ingestSave and delete turns (/turns, /turns/batch, DELETE /turns/{turn_id}).
recallRead only (/recall).

Keys are also scoped: a project-scoped key reaches every tenant in the project; a tenant-scoped key reaches only the tenants it lists. Calling outside a key's scope returns 403 scope_denied. A common production setup is one project-scoped admin key on your server and narrow ingest and recall keys per service.


Error codes
Stable codes for every failure mode.
HTTPCodeMeaning
401auth_requiredMissing, malformed, or revoked key.
402payment_requiredDeveloper credit balance is empty. Ingest pauses until credits are added; stored memories and recall are unaffected.
403role_requiredKey's role does not permit this endpoint.
403scope_deniedKey is not scoped to this tenant.
404not_foundTenant or resource does not exist or is deleted.
409conflictDuplicate tenant_id, tenant not in a usable state, or a turn still being processed.
422validation_failedRequest body failed validation; the message names the field.
429rate_limitedPlan cap reached. Stored memories and recall are unaffected.
500internal_errorSomething failed on our side.

GET /v1/health

No authentication. Returns 200 when the API is up. Point your uptime checks here.


Tenants
A tenant is one isolated memory store, typically one per end user. Physically separate databases per tenant: no shared tables, no shared credentials, no row filters.
POST /v1/tenants

Provision a tenant. Requires admin.

FieldTypeNotes
tenant_idRequired stringYour identifier for this user. Unique within the project.
Shell
curl -X POST https://api.leapmemory.com/v1/tenants \
  -H "Authorization: Bearer $LM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id": "user_482"}'
Response · 201
{
  "success": true, "http_status": 201, "code": "created",
  "data": {
    "tenant_id": "user_482",
    "status": "ready",
    "created_at": "2026-07-10T09:39:11.548594+00:00"
  }
}

Provisioning is synchronous: when the call returns, the tenant is ready. A duplicate tenant_id returns 409 conflict.

GET /v1/tenants

Any role. Returns the tenants visible to the key's scope; deleted tenants are excluded.

Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": { "tenants": [
    { "tenant_id": "user_482", "status": "ready", "created_at": "..." }
  ] }
}
GET /v1/tenants/{tenant_id}

Any role within scope. Returns the same tenant_id / status / created_at object, or 404.

DELETE /v1/tenants/{tenant_id}

Requires admin. Soft by default: the tenant stops serving but its storage is kept and it can be restored. Add ?hard=true to tear down every database permanently.

Shell
curl -X DELETE "https://api.leapmemory.com/v1/tenants/user_482?hard=true" \
  -H "Authorization: Bearer $LM_KEY"
Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": { "deleted": true, "tenant_id": "user_482" }
}
Hard deletion is structural: the tenant's databases are dropped entirely, not scanned for rows. Nothing is recoverable afterwards. This is the compliance answer for "erase this user."
POST /v1/tenants/{tenant_id}/restore

Requires admin. Brings a soft-deleted tenant back; storage was kept alive, so restore is instant. Restoring a tenant that is not deleted returns 409.

Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": { "restored": true, "tenant_id": "user_482" }
}

Memory
Save what was said, recall it whenever it matters.
POST /v1/tenants/{tenant_id}/turns

Save a turn. Requires ingest.

FieldTypeNotes
roleRequired stringWho spoke, e.g. user or assistant.
contentRequired stringThe words, verbatim. Up to 100,000 characters.
speaker_idOptional stringDistinguish speakers in multi-party conversations. Defaults from role.
tsOptional datetimeWhen it was said. Defaults to now. Set it when importing history.
Response · 201
{
  "success": true, "http_status": 201, "code": "accepted",
  "data": {
    "turn_id": "6a7892b0-46e9-454f-a225-fe321d006fb5",
    "role": "user",
    "speaker_id": "user",
    "status": "pending",
    "ts": "2026-07-10T09:39:14.949785Z"
  }
}
Ingest is asynchronous. accepted means the verbatim words are stored; extraction runs in the background and typically completes within seconds. One saved memory is billed per turn. See Billing.
POST /v1/tenants/{tenant_id}/turns/batch

Save 1–100 turns in parallel. Requires ingest. Body is {"turns": [ ... ]} with the same fields as a single turn. Use it for importing conversation history, with ts set on each turn.

Response · 201
{
  "success": true, "http_status": 201, "code": "accepted",
  "data": {
    "turns": [ { "turn_id": "...", "status": "pending", ... } ],
    "count": 3
  }
}
POST /v1/tenants/{tenant_id}/recall

Recall memories for a query. Requires recall. Free: recall never consumes credits or counts against a plan.

FieldTypeNotes
queryRequired stringNatural language, up to 10,000 characters. Any language.
speaker_idOptional stringOnly memories from this speaker.
anchor_entityOptional stringPin retrieval to one entity by name.
start, endOptional datetimeLimit to a time window.
Shell
curl -X POST https://api.leapmemory.com/v1/tenants/user_482/recall \
  -H "Authorization: Bearer $LM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "where does Sam work?"}'
Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": {
    "facts": [
      {
        "subject": "sam",
        "verb": "works-at",
        "object": "beacon",
        "type_name": "works-at",
        "confidence": 0.99,
        "mention_count": 1,
        "last_mentioned": "2026-07-10T09:39:23.295529+00:00",
        "sentence": "Sam works at Beacon."
      }
    ],
    "chunks": [
      {
        "chunk_id": "6a7892b0-46e9-454f-a225-fe321d006fb5:0",
        "turn_id": "6a7892b0-46e9-454f-a225-fe321d006fb5",
        "content": "Sam works at Beacon. He owns the auth service and pairs with Aisha.",
        "role": "user",
        "speaker_id": "user",
        "score": 0.9945,
        "importance": 0.5,
        "created_at": "2026-07-10T09:39:23.319353Z"
      }
    ],
    "anchors_found": [
      { "name": "sam", "type_name": "person", "count": 1, "span_start": 11, "span_end": 14 }
    ]
  }
}
SectionWhat it is
factsDistilled subject-verb-object statements with confidence, mention count, and the exact sentence each came from.
chunksThe verbatim words as they were said, ranked by relevance score.
anchors_foundEntities detected in your query, with type and character span, that steered retrieval.

Feed facts and top chunks into your model's context, and cite sentence when your product needs to show where a memory came from.

GET /v1/tenants/{tenant_id}/briefing

The tenant's ambient picture: who this person is, as one ready-to-inject text block. Requires recall. Free, like recall.

Recall answers questions; the briefing needs none. It is built for the moment before a conversation starts: load it once when a session opens, place it in your model's system context as background knowledge, and let recall handle everything specific from there. The user's own facts come first, their most established relationships and preferences ahead of everything, followed by the freshest recent context. It is computed live from the memory on every call, so it can never go stale.

Shell
curl https://api.leapmemory.com/v1/tenants/user_482/briefing \
  -H "Authorization: Bearer $LM_KEY"
Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": {
    "text": "- Sam works at Beacon.\n- Sam owns the auth service.\n- Sam pairs with Aisha.",
    "facts_included": 3
  }
}
FieldWhat it is
textThe briefing, one fact per line, capped to stay small enough to sit in a system prompt without crowding the conversation.
facts_includedHow many facts made the cut.

A brand-new tenant returns an empty text with facts_included: 0: inject nothing and the conversation starts like meeting someone new. When you place the briefing in context, frame it as quiet background the model uses only when relevant, so it informs answers without being recited.

Pull the briefing once per session, not per message. Per-message context belongs to recall.
DELETE /v1/tenants/{tenant_id}/turns/{turn_id}

Delete one turn and everything derived from it. Requires ingest. Removes the verbatim turn, its recallable chunks, and any facts in the memory graph that came only from this turn. A fact also supported by other turns survives, with this turn's contribution removed. Free: deletion never consumes credits.

Shell
curl -X DELETE https://api.leapmemory.com/v1/tenants/user_482/turns/6a7892b0-46e9-454f-a225-fe321d006fb5 \
  -H "Authorization: Bearer $LM_KEY"
Response · 200
{
  "success": true, "http_status": 200, "code": "ok",
  "data": { "deleted": true, "turn_id": "6a7892b0-46e9-454f-a225-fe321d006fb5" }
}

A turn that is still pending returns 409 conflict; retry once extraction settles. An unknown or already-deleted turn_id returns 404. Deleting the same turn twice is safe: the second call is the 404.

Deletion is structural and immediate: the turn's words, chunks, and solely-derived facts are removed from the primary stores and search indexes in the same request.