Skip to main content
Backfilling a space (from a CRM export, chat transcripts, a support ticket history) means writing many memories at once, and each one takes a couple of seconds to extract and index. This guide covers the pattern that avoids blocking on that: batch ingest plus a webhook, so you never poll.

Step 1: queue the batch

record/batch accepts 1 to 100 items in one call and is always asynchronous. You get a job_id back immediately, the extraction happens in the background.
Set timestamp on every item you can. It is the event time (when the thing happened), and ranking is recency-aware, so an undated backfill arrives looking uniformly fresh and competes with genuinely recent memories. Note that it does not change when the memory was recorded, so as_of still sees the whole import as having landed today. See Searching over time.
More than 100 items to import? Chunk them into multiple record/batch calls. There’s no cost benefit to queuing versus writing synchronously, only a latency one, so chunking costs nothing extra.

Step 2: register a webhook once, instead of polling every batch

You can poll GET /v1/spaces/{space_id}/jobs/{job_id} until status is terminal, but for a bulk import that’s a lot of polling loops for not much information. Register a webhook instead and get told when each item lands:
The response includes secret once. Store it immediately, it’s never shown again and you need it to verify deliveries.
A new webhook can take up to 15 seconds before it starts receiving events. If you register the webhook and then immediately fire the batch, the first item or two may be missed. Register it, wait a moment, then queue the import.

Step 3: verify and handle deliveries

Every delivery is signed. Verify the raw request body, not the parsed JSON, because reserializing changes byte order and breaks the signature:
Acknowledge with any 2xx fast: deliveries time out after 10 seconds, and a slow handler gets treated as failed and retried, which turns into duplicate deliveries. Do the real work after you’ve returned the response, and make it idempotent on operation_id since delivery is at-least-once.

Track overall progress

For a large import you’ll usually want a “is the whole thing done” view, not just per-item events. Two options, not mutually exclusive:
  • Poll the batch’s job_id (GET /v1/spaces/{space_id}/jobs/{job_id}) at a slow interval (e.g. every 10–30s) purely for the top-level completed/failed status.
  • Count memory.created webhook deliveries against accepted from the batch response, if you want per-item completion in your own system without polling at all.

Common mistakes

  • Polling the job status quickly and often. It’s a real endpoint hit; for a bulk import a webhook is strictly better. Reserve polling for “did the whole batch finish” checks, not per-item status.
  • Re-serializing the webhook body before verifying it. Breaks the HMAC. Verify the raw bytes.
  • Holding the webhook connection open while you process. Acknowledge first, work after.
  • Sending more than 100 items in one record/batch call. It’s rejected, so chunk it.

Next steps

Memories API

Full record and record/batch reference.

Webhooks API

Events, retries, delivery debugging.