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

FieldRequiredDescription
inputsYes Array of content items. Several items in one call are processed together, so a whole conversation turn set can be sent at once.
thread_idNo Thread to attach this content to. Omit for agent-global memory visible from every thread.
task_idNo Shared task pool. Facts also land in that pool, visible to every agent using the same id.
instructionsNo Free-text guidance for this extraction, up to 2000 characters. See Steer what gets stored.
asyncNo When true, return as soon as the write is queued instead of waiting for extraction. See Queued writes.

Input items

FieldRequiredDescription
kindYesSource type. One of SYSTEM, USER, AGENT, TOOL, DOCUMENT, CODE. Determines trust, see source trust.
contentYesThe text to extract from. For file inputs, base64 of the file.
content_typeYesMIME type of content, for example text/plain or application/pdf.
authorNoWho produced this turn, for example "Alice". Used to attribute facts during extraction.
event_dateNoWhen the content was authored. Anchors relative phrases like "last Tuesday". Defaults to now.
pathNoWhich 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.
deletedNoWhen 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.

  • USER for whatever the end user said.
  • AGENT for your assistant's own output.
  • TOOL for tool and sub-agent results.
  • DOCUMENT for reference material you are loading in bulk.
  • CODE for source files, config, and schemas.
  • SYSTEM for 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.