Skip to main content
POST
TypeScript SDK

Authorizations

x-api-key
string
header
required

Long-lived org API key. Alternative: Authorization: Bearer <key>.

Query Parameters

wait
boolean
default:false

When true, hold the connection up to ~30s waiting for extraction to terminate. Returns 200 + terminal job inline on success; falls back to 202 + pending on timeout. Default false → 202 + pending immediately.

Body

application/json

POST /v1/memories — async ingest from a message list.

Required entities: user_id and conv_id. user_id scopes a user's per-user memory namespace, so a user's facts accumulate in one place rather than fragmenting per-conversation. conv_id anchors every extracted memory to a conversation for replay, export, and bulk retract. agent_id and app_id remain optional — set either, both, or neither. There is no auto-default app_id rule.

extract_artifacts opts in to the artifact-extraction stage (off by default — the most expensive stage and most callers don't need it). Episodes are always extracted (conv_id is guaranteed). Facts are always extracted.

There is no client-facing pipeline hint: the server selects its extraction strategy automatically based on the number of messages.

messages
Message · object[]
required

Chat-style turns to extract memories from. Must be non-empty — an empty list returns 400 invalid_messages (the route raises this explicitly so the wire error carries the stable code rather than a generic Pydantic validation message). Server picks live vs batch extraction by length; no client-facing strategy hint.

user_id
string
required

User identifier. REQUIRED. Keys the per-user session namespace so a user's facts accumulate across their conversations rather than fragmenting per-conv. Also stored as an indexed filter axis on every row.

Minimum string length: 1
Example:

"alice"

conv_id
string
required

Conversation identifier. REQUIRED. Anchors every extracted memory to a conversation for replay, export, and bulk retract.

Minimum string length: 1
Example:

"conv-2026-05-15-abc"

agent_id
string | null

Optional agent scope. Indexed alongside the other entity ids.

app_id
string | null

Optional app scope. Indexed alongside the other entity ids.

timestamp_format
string | null

Optional strptime format string used to parse each message's date field into a real timestamp on the batch-extraction path (e.g. "%Y-%m-%d %H:%M:%S"). When omitted, or when a date value fails to parse, the turn keeps its raw date string with no parsed timestamp. Only consulted on the batch path (message count above the live threshold); the live path ignores it.

Example:

"%Y-%m-%d %H:%M:%S"

extract_artifacts
boolean
default:false

When true, extracted artifacts are also stored and returned as artifact memories, in addition to fact + episode extraction. Off by default — most expensive stage and most callers don't need it. Routing (live vs batch) is unaffected and still chosen by message count.

agentic
boolean
default:false

When true, ingest through the agentic (task-aware) path: recall-first extraction + a Stage-2 noise filter + agentic artifact detection + a structured session gist. Intended for tool-using / coding-agent transcripts. Off by default (conversational extraction).

group_ids
string[]

Optional list of group ids the client wants associated with this ingest. Each id must be a registered group on the org (see POST /v1/groups). Ids that are unknown or archived are dropped silently and echoed back in result.ignored_group_ids — a single stale id will not fail the ingest, since the chat path tolerates partial tagging better than a hard reject. After extraction, a classifier judges each memory personal-vs-shareable: personal memories are never group-tagged (they stay in the author's personal scope); shareable memories are tagged with every prompt-less (catch-all) group in the valid subset, plus whichever prompted groups the classifier matched. Tagged rows become reachable via filters: {group_ids: <id>} on search. The capped length is MAX_GROUP_IDS_PER_INGEST.

Response

Inline terminal response. Returned when ?wait=true is set and the extraction pipeline completes inside the wait window (~30s). Body is the terminal IngestJobResponse with status: "succeeded" (carrying result) or "failed" (carrying error).

Returned by POST /v1/memories (with status 202 by default, 200 when ?wait=true succeeds inline) and by GET /v1/memories/jobs/{job_id}. Same wire shape across every read of a job's lifecycle.

id
string
required

Opaque job id of the form job_<32-hex-chars>.

Example:

"job_a1b2c3d4e5f6071829304a5b6c7d8e9f"

status
enum<string>
required

Lifecycle state. pending → enqueued. running → extraction in progress. succeededresult is set. failederror is set. Terminal jobs (succeeded / failed) are retained for 24h before TTL sweep returns 404 job_not_found.

Available options:
pending,
running,
succeeded,
failed
created_at
string<date-time>
required

ISO-8601 timestamp the job was created.

object
string
default:ingest_job

Constant discriminator for the resource type.

Allowed value: "ingest_job"
updated_at
string<date-time>

ISO-8601 timestamp of the most recent state transition.

result
IngestResult · object | null

Populated when status = succeeded; null otherwise.

error
IngestJobError · object | null

Populated when status = failed; null otherwise.