Guides
Ingestion
Send raw content. Recalld extracts facts and compares them with existing memory. New information can update or supersede older facts.
POST /v1/agents/{agent_id}/memory
Request body
| Field | Required | Description |
|---|---|---|
| inputs | Yes | Array of content items. Several items in one call are processed together, so a whole conversation turn set can be sent at once. |
| thread_id | No | Thread to attach this content to. Omit for agent-global memory visible from every thread. |
| task_id | No | Shared task pool. Facts also land in that pool, visible to every agent using the same id. |
| instructions | No | Free-text guidance for this extraction, up to 2000 characters. See Steer what gets stored. |
| async | No | When true, return as soon as the write is queued instead of waiting for extraction. See Queued writes. |
Input items
| Field | Required | Description |
|---|---|---|
| kind | Yes | Source type. One of SYSTEM, USER, AGENT, TOOL, DOCUMENT, CODE. Determines trust, see source trust. |
| content | Yes | The text to extract from. For file inputs, base64 of the file. |
| content_type | Yes | MIME type of content, for example text/plain or application/pdf. |
| author | No | Who produced this turn, for example "Alice". Used to attribute facts during extraction. |
| event_date | No | When the content was authored. Anchors relative phrases like "last Tuesday". Defaults to now. |
| path | No | Which document this is: a filename for DOCUMENT, a repository-relative file path for CODE. Re-ingest supersession is keyed on it for CODE. Usable as a retrieval filter for any kind. |
| deleted | No | When true, supersedes every fact for that path with no replacement. Use when a file is removed. |
Example
curl -X POST https://eu.recalld.ai/v1/agents/$AGENT_ID/memory \
-H "Authorization: Bearer $RECALLD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"thread_id": "'"$THREAD_ID"'",
"inputs": [
{
"kind": "USER",
"author": "Alice",
"content": "Bob prefers morning meetings and uses a standing desk.",
"content_type": "text/plain",
"event_date": "2026-08-20T09:14:00Z"
},
{
"kind": "AGENT",
"content": "Noted. I will schedule Bob before 11am from now on.",
"content_type": "text/plain"
}
]
}'
The response does not contain the facts
Ingestion confirms the write completed. To see what was extracted, run a retrieval call or open the Threads page.
Queued writes
Extraction takes seconds to a couple of minutes, and a chat application rarely
needs to wait for it. Set "async": true and the call returns
202 as soon as the write is queued.
{
"job_id": "5b2c…",
"status": "queued"
}
Every write goes through the same queue, whether or not it asks for
async. Writes to one thread are processed strictly in the order
they arrive, so a queued turn is never overtaken by a later one, and a
synchronous call made while earlier writes are still queued waits for them.
Writes to different threads run in parallel.
Poll the job to see whether it finished. Jobs stay queryable for seven days.
GET /v1/agents/{agent_id}/memory/jobs/{job_id}
{
"job_id": "5b2c…",
"status": "completed",
"created_at": "2026-09-09T10:00:00Z",
"finished_at": "2026-09-09T10:00:41Z"
}
status is one of queued, processing,
completed or failed. A failed job carries an
error field with the same message a synchronous call would have
returned, for example a backdated event_date.
Queued writes are billed when they finish, at the same rate as synchronous ones. Nothing is charged for a job that is still waiting.
Batch ingestion
To load a large history, such as a backfill of past conversations, upload it as
one batch instead of sending thousands of calls. Recalld ingests each memory
addition exactly as POST /v1/agents/{agent_id}/memory would, in
upload order, on the model provider's Flex tier. That is slower than normal
ingestion, so batches suit backfills rather than live chat. In exchange, the LLM
tokens of a batch are billed at the model's Flex rate, half the normal rate. The
per-request fee and embeddings are billed as usual.
The body is JSON lines: one memory addition per line, with the same fields as the
ingestion body plus agent_id. A batch can span many agents and
threads; additions to the same thread are processed in the order they appear.
Uploads are limited to 512 MB, and task_id is not supported.
curl -X POST https://eu.recalld.ai/v1/memory/batches \
-H "Authorization: Bearer $RECALLD_API_KEY" \
-H "Content-Type: application/jsonl" \
--data-binary @history.jsonl
{"agent_id": "…", "thread_id": "…", "inputs": [{"kind": "USER", "author": "Alice", "content": "Bob prefers morning meetings.", "content_type": "text/plain", "event_date": "2026-08-20T09:14:00Z"}]}
{"agent_id": "…", "thread_id": "…", "inputs": [{"kind": "AGENT", "content": "Noted.", "content_type": "text/plain", "event_date": "2026-08-20T09:15:00Z"}]}
The upload is checked line by line before anything is stored; an invalid line rejects the whole upload with its line number. The response is the batch. Poll it until it finishes:
GET /v1/memory/batches/{id}
{
"id": "9f1e…",
"status": "in_progress",
"counts": { "total": 681, "completed": 120, "failed": 0 },
"created_at": "2026-10-11T16:13:32Z"
}
counts.total is the number of memory additions uploaded,
completed how many are stored and failed how many could
not be. status is in_progress until every addition is
stored or has failed, then completed, or failed when none
could be stored.
To stop a batch, call POST /v1/memory/batches/{id}/cancel. It moves to
cancelling and, within about a minute, to cancelled.
Memory additions already stored stay stored and are billed; the rest are dropped.
GET /v1/memory/batches lists your latest batches, and the Batches page
in the dashboard shows them and can cancel one.
A batch needs an API key that is not limited to some agents. Every LLM model the
agent's ingestion uses must support batches (batch in
GET /v1/models), and models on your own provider keys are not
supported.
Data residency
Batch processing can run in a different place from normal ingestion with the
same model. On the EU host, a batch with a model that is not batch-processed in
the EU (batch_eu in GET /v1/models) is refused unless
you add ?allow_non_eu=true. Normal ingestion is not affected.
Get authorship right
Extraction uses kind and author to work out who a
statement is about. Sending an assistant reply as USER is the most
common mistake, and it produces facts attributed to the wrong person.
USERfor whatever the end user said.AGENTfor your assistant's own output.TOOLfor tool and sub-agent results.DOCUMENTfor reference material you are loading in bulk.CODEfor source files, config, and schemas.SYSTEMfor environment facts that must never be overwritten.
author is who produced the turn, so keep it a person or system name.
It is not the place to record which document something came from: name the document
in path instead. Extraction writes the author's name into the facts it
produces, so a document title there ends up phrased as if the document were speaking.
Both are usable as retrieval filters, so an agent can answer from one uploaded file rather than from everything in the thread.
Date historical content
If you are backfilling old conversations, set event_date per item.
Without it every message is treated as authored now, relative dates resolve
against today, and the temporal ordering that recall depends on is lost.
Steer what gets stored
instructions is free text that guides extraction for one request. Use it
to keep a category out of memory, or to bias extraction toward what your application
actually needs.
{
"instructions": "Do not store payment card numbers or home addresses. Focus on order status and delivery dates.",
"inputs": [ ... ]
}
It applies while the extractor decides what to pull out of the content, so excluded material is never turned into a fact, never embedded, and never stored. It cannot change the response format or override the extraction rules. Omit the field and extraction behaves exactly as documented everywhere else.
Instructions are per request, so different content can carry different guidance on the same agent. Keep them short and concrete: long or contradictory guidance gives the extractor more to weigh and makes results less predictable.
Cost
Ingestion runs the extraction pipeline and consumes credits. So does writing a fact directly, because the text still has to be embedded. Reading a thread's messages does not.