Every endpoint, request field, and error code. Plain HTTPS against api.leapmemory.com.
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.
# 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.
| Role | Can call |
|---|---|
| admin | Everything: tenant management and all memory operations. |
| ingest | Save and delete turns (/turns, /turns/batch, DELETE /turns/{turn_id}). |
| recall | Read only (/recall, /briefing, /turns/status). |
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.
| HTTP | Code | Meaning |
|---|---|---|
| 401 | auth_required | Missing, malformed, or revoked key. |
| 402 | payment_required | Developer credit balance is empty. Ingest pauses until credits are added; stored memories and recall are unaffected. |
| 403 | role_required | Key's role does not permit this endpoint. |
| 403 | scope_denied | Key is not scoped to this tenant. |
| 404 | not_found | Tenant or resource does not exist or is deleted. |
| 409 | conflict | Duplicate tenant_id, tenant not in a usable state, or a turn still being processed. |
| 422 | validation_failed | Request body failed validation; the message names the field. |
| 429 | rate_limited | Plan cap reached. Stored memories and recall are unaffected. |
| 500 | internal_error | Something failed on our side. |
No authentication. Returns 200 when the API is up. Point your uptime checks here.
Provision a tenant. Requires admin.
| Field | Type | Notes |
|---|---|---|
| tenant_id | Required string | Your identifier for this user. Unique within the project. |
curl -X POST https://api.leapmemory.com/v1/tenants \
-H "Authorization: Bearer $LM_KEY" \
-H "Content-Type: application/json" \
-d '{"tenant_id": "user_482"}'
{
"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.
tenant_id was soft-deleted, the 409 says so, and its data is still intact. Restore it instead of creating it again, or remove it permanently with ?hard=true before reusing the name.Any role. Returns the tenants visible to the key's scope. Soft-deleted tenants are excluded by default.
| Query | Type | Notes |
|---|---|---|
| include_deleted | boolean | Default false. Set to true to list soft-deleted tenants too. They come back with status: "deleted" and can be restored. |
{
"success": true, "http_status": 200, "code": "ok",
"data": { "tenants": [
{ "tenant_id": "user_482", "status": "ready", "created_at": "..." }
] }
}
Any role within scope. Returns the same tenant_id / status / created_at object plus the two name lists below, or 404.
Requires admin. Sets the tenant's label and, optionally, who the two speakers are.
| Field | Type | Notes |
|---|---|---|
| label | string | Written on every call. Sending an empty string clears it. |
| owner_names | string[] | The names that mean the end user in this tenant: what they are called, a username, an address. Up to 10. Omit the field to leave the current list alone; send [] to clear it. |
| companion_names | string[] | The names that mean your assistant, if it has one it is spoken to by. Same rules. |
curl -X PATCH https://api.leapmemory.com/v1/tenants/user_482 \
-H "Authorization: Bearer $LM_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "", "owner_names": ["john"], "companion_names": ["wren"]}'
Names are normalized on write: trimmed, lowercased, deduplicated. Non-ASCII letters are preserved, so nuhoglu and nuhoğlu are two entries and both can be registered.
role, LeapMemory needs to know which strings mean the user. Without them it still refuses to record facts about the assistant, but it also cannot attribute to the user what the assistant said about them: "your leg still hurts?" becomes a fact about nobody. You do not need the names at tenant creation. Send this call the moment you learn them, once.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.
curl -X DELETE "https://api.leapmemory.com/v1/tenants/user_482?hard=true" \ -H "Authorization: Bearer $LM_KEY"
{
"success": true, "http_status": 200, "code": "ok",
"data": {
"deleted": true, "tenant_id": "user_482",
"mode": "hard", "restorable": false
}
}
mode reports which delete actually ran, "soft" or "hard", and restorable is true only after a soft one. Read them rather than assuming: a call without ?hard=true keeps every byte of the tenant's data.
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.
{
"success": true, "http_status": 200, "code": "ok",
"data": { "restored": true, "tenant_id": "user_482" }
}
Save a turn. Requires ingest.
| Field | Type | Notes |
|---|---|---|
| role | Required string | Who spoke, e.g. user or assistant. If you send assistant turns, register the speakers first with PATCH /v1/tenants/{id}; LeapMemory never records a fact about the assistant, and the names are what let it attribute to the user what the assistant said about them. |
| content | Required string | The words, verbatim. Up to 100,000 characters. |
| speaker_id | Optional string | Distinguish speakers in multi-party conversations. Defaults from role. |
| ts | Optional datetime | When it was said. Defaults to now. Set it when importing history. |
{
"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"
}
}
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.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.
{
"success": true, "http_status": 201, "code": "accepted",
"data": {
"turns": [ { "turn_id": "...", "status": "pending", ... } ],
"count": 3
}
}
Recall memories for a query. Requires recall. Free: recall never consumes credits or counts against a plan.
| Field | Type | Notes |
|---|---|---|
| query | Required string | Natural language, up to 10,000 characters. Any language. |
| speaker_id | Optional string | Only memories from this speaker. |
| anchor_entity | Optional string | Pin retrieval to one entity by name. |
| start, end | Optional datetime | Limit to a time window. |
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?"}'
{
"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 }
]
}
}
| Section | What it is |
|---|---|
| facts | Distilled subject-verb-object statements with confidence, mention count, and the exact sentence each came from. |
| chunks | The verbatim words as they were said, ranked by relevance score. |
| anchors_found | Entities 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.
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.
curl https://api.leapmemory.com/v1/tenants/user_482/briefing \ -H "Authorization: Bearer $LM_KEY"
{
"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
}
}
| Field | What it is |
|---|---|
| text | The briefing, one fact per line, capped to stay small enough to sit in a system prompt without crowding the conversation. |
| facts_included | How 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.
recall.Ingest progress for a tenant: how many turns are stored, how many are fully digested, and whether any failed. Requires recall. Free, like recall.
Ingest is asynchronous: accepted means the words are stored, and extraction finishes in the background. This endpoint tells you when that work is done. After importing history, poll it and flip your product to ready when indexed equals total. It also surfaces the ids of any turns that could not be processed, so a failure is never silent.
curl https://api.leapmemory.com/v1/tenants/user_482/turns/status \ -H "Authorization: Bearer $LM_KEY"
{
"success": true, "http_status": 200, "code": "ok",
"data": {
"total": 500,
"pending": 12,
"indexed": 487,
"failed": 1,
"failed_ids": ["6a7892b0-46e9-454f-a225-fe321d006fb5"]
}
}
| Field | What it is |
|---|---|
| total | Turns stored for this tenant. |
| pending | Stored but still being digested. Not yet recallable. |
| indexed | Fully digested and recallable. |
| failed | Turns that could not be processed after retries. The verbatim words are still stored safely. |
| failed_ids | The turn_id of each failed turn. |
A failed count is often temporary: turns are retried automatically in the background, so a turn can move from failed back to indexed on its own. Treat a failure as final only when it persists.
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.
curl -X DELETE https://api.leapmemory.com/v1/tenants/user_482/turns/6a7892b0-46e9-454f-a225-fe321d006fb5 \ -H "Authorization: Bearer $LM_KEY"
{
"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.
What this key's project has consumed, so you can put it in your own cost. Scoped to the key's project and nothing else. Free, and never billed.
Every call LeapMemory serves is metered. This is that meter, read back: writes, recalls, and briefings, over a window you choose. If you resell memory inside your own product, this is the number you bill against. A key scoped to specific tenants sees only those tenants, and its totals are summed from them alone.
curl "https://api.leapmemory.com/v1/usage?from=2026-09-01&to=2026-09-30&by_tenant=true" \ -H "Authorization: Bearer $LM_KEY"
| Query | What it is |
|---|---|
| from | YYYY-MM-DD. Defaults to the first of the current month. |
| to | YYYY-MM-DD, inclusive of the day named. Defaults to today. |
| by_tenant | true adds a per-tenant breakdown. Off by default. |
{
"success": true, "http_status": 200, "code": "ok",
"data": {
"period": { "from": "2026-09-01", "to": "2026-09-30" },
"totals": { "ingest": 1420, "recall": 903, "briefing": 210 },
"by_endpoint": {
"turns.ingest": 1180,
"turns.ingest_batch": 240,
"memories.recall": 903,
"memories.briefing": 188,
"memories.briefing_init": 22
},
"tenants": [
{ "tenant_id": "user_482", "ingest": 96, "recall": 74, "briefing": 12,
"by_endpoint": { "turns.ingest": 96, "memories.recall": 74 } }
]
}
}
| Field | What it is |
|---|---|
| totals.ingest | Turns written, single and batch together. This is the metered unit. |
| totals.recall | Recall calls. Free, counted so you can see the read load. |
| totals.briefing | Briefings served, including the one a connector pulls when a session opens. |
| by_endpoint | The raw counters behind the totals, so you can reconcile a number yourself instead of trusting the fold. |
| tenants | Present only with by_tenant=true. Same shape, one entry per tenant that had activity. |