Memory API

What to send and how to split it

The unit recall reads best, the size of one data point, the shape of its text, and the procedure for a historical load.

Copy page
View as Markdown

The unit

One data point is one thing that happened. It is one piece of raw text plus its time. The unit of replacement and deletion is the data point. Send one content value per data point, and set label and timestamp for each one.

Size

  • content: at most 500,000 characters. It must be non-blank and must not contain U+0000.
  • Batch: 1 to 1,000 items and at most 16 MiB of UTF-8 in total per batch request.
  • label: at most 200 characters.
  • id: at most 512 characters, with no /.
  • metadata: a JSON object of at most 64 KiB when serialized.

content over the limit returns 413 content-too-large. Any other field over its limit returns 400 invalid-ingestion, and its debugMessage names the field.

What the text looks like

The source can be a chat or thread, an email, a call transcript, a CSV row, a JSON record or a document. Cut a long source into parts, one thing that happened per part. A chat message looks like this:

#support, 2026-04-02
Ana: The export is ready for review.
Ben: Thanks, sending it to the client now.

Ids

The default id is the lowercase SHA-256 of content. Set your own id when you need to replace the data point later, because a send with the same id and changed content becomes a new revision.

For a long source split into parts, use <base>.<n> as the id of each part.

Timestamps

Send timestamp in ISO 8601 with a zone, for example 2026-10-26T09:14:00+01:00. Send the time the thing happened, not the time you send it. If you omit it, a resend keeps the stored value and a first send uses the current time. Recall returns it as occurredAt and filters on it with queryTimestamp, occurredFrom and occurredTo.

Load old data

Use these steps to bring in data you already have, such as past emails, chats, call transcripts and documents. This is called a historical load.

  1. Cut the old source into data points that follow the rules above.
  2. Estimate the load with POST /v1/memory/ingest/estimate. It cuts and batches your files without sending them, so you see the batches before any data leaves your side.
  3. Send the data points in batches with POST /v1/memory/ingest/batch. Set one idempotencyKey per batch. A retry with the same key and the same body returns the original receipt. A reused key with a different body returns 409 idempotency-conflict.
  4. Wait for the send to settle. Poll GET /v1/memory/ingest/{ingestionId}. status is processing, failed or completed. settled is true when nothing is queued. blocked is true when items are set aside after repeated failures and nothing is queued.
  5. Verify the result with a recall, and check readiness and failure. For a refusal at item k, the batch error carries data.accepted. Send the rest again with the same idempotencyKey and body, and the send resumes at k. To re-run a send that stopped, call POST /v1/memory/ingest/{ingestionId}/retry.

Corrections and deletion

  • To correct a data point, send the same id with the new content. Harny deletes the memories built on the old text and then ingests the new text. Fields you leave out keep their stored values.
  • To delete a send, call DELETE /v1/memory/ingest/{ingestionId}. It returns 204.
  • To delete one data point, call DELETE /v1/memory/data-points/{sourceId}. It returns 202.
  • To delete many, call POST /v1/memory/data-points/delete with up to 1,000 ids. A missing id returns 404 and nothing is deleted.
  • A deleted id sent again returns 409 data-point-deleted.

Deleting a data point removes the memories the send created. Memories that existed before and were shared with it stay.