Korely

Batch & status

Batch import

Bulk-import up to 500 memories in one async call. Korely enqueues the job and returns a job id immediately; each item is imported later through the same pipeline as a single add.

POST /v1/batch

Use this when you're backfilling history or seeding a namespace and don't want to fire hundreds of individual POST /v1/memories calls. The request returns 202 Accepted with a job id; a background worker imports each item, running embeddings, typed-fact extraction, and contradiction checking, exactly as a single add would. Poll GET /v1/batch/{job_id} for progress.

Authentication

HTTP header, required: Authorization: Bearer kor_live_.... The key must carry the memories:write scope.

Request body

FieldTypeRequiredDescription
memoriesarray<object>RequiredThe memory objects to import. 1-500 items. Each element is a BatchMemory (see fields below).

Each BatchMemory element has these fields:

FieldTypeRequiredDescription
contentstringRequiredThe memory text. 1-16,000 characters.
user_idstring · nullOptionalThe end-user namespace this memory belongs to. Default null. Max 255 chars.
agent_idstring · nullOptionalYour application's namespace. Default null. Max 255 chars.
run_idstring · nullOptionalOne session or conversation. Default null. Max 255 chars.
metadataobject · nullOptionalArbitrary JSON stored alongside the memory and echoed back on reads. Default null.

Example request

Terminal window
curl -X POST https://api.korely.ai/v1/batch \
-H "Authorization: Bearer kor_live_..." \
-H "Content-Type: application/json" \
-d '{
"memories": [
{
"content": "User prefers email follow-ups, not phone",
"user_id": "customer-giulia-4812",
"agent_id": "support-bot"
},
{
"content": "Account is on the EU data region",
"user_id": "customer-giulia-4812",
"agent_id": "support-bot"
},
{
"content": "Renewal date is 2026-09-01",
"user_id": "customer-giulia-4812",
"agent_id": "support-bot",
"metadata": { "source": "crm" }
}
]
}'

Response

202 Accepted. The job has been enqueued; nothing is imported yet. Poll GET /v1/batch/{job_id} to track progress.

{
"id": "job_8f2c1aab4d7e4f0c9a1b2c3d4e5f6a7b",
"status": "processing",
"received": 3
}
FieldTypeDescription
idstringOpaque batch job id, prefix job_ followed by the UUID hex, e.g. job_8f2c1aab4d7e4f0c9a1b2c3d4e5f6a7b. Use it to poll GET /v1/batch/{job_id}.
statusstringAlways processing in the POST response. (The persisted job starts in pending and advances as the worker drains it.)
receivedintegerNumber of memory objects accepted into the job, equals the length of the memories array you sent.

Errors

StatusCodeCause
401invalid_keyMissing or invalid API key. No Bearer credential was supplied, or the kor_live_ key does not resolve to a live key.
403forbiddenThe API key lacks the memories:write scope.
422invalid_requestRequest validation failed, memories is empty or has more than 500 items, a content is empty or over 16,000 chars, or a user_id / agent_id / run_id exceeds 255 chars.
429rate_limit_exceededPer-tier fixed-window request rate limit hit. Comes back with a Retry-After header. This is the per-minute / hour / day request limit, distinct from the monthly write quota, which is enforced per item inside the worker, not at POST time.

Notes

  • It's asynchronous. The POST only enqueues the job and returns immediately (202). A background worker imports each item later through the same pipeline as POST /v1/memories, engine.add plus best-effort typed-fact extraction.
  • Each item counts as one write. Every imported item is checked against the per-agent namespace cap first, then your monthly write quota, so a capped item never burns a quota count.
  • Quota mid-batch fails gracefully. Once the monthly write quota is hit, the remaining items fail individually with a quota error (no silent overage) and are recorded in the job's errors array. They do not 429 the original POST.
  • Webhooks fire per item. The worker emits a memory.created webhook for each successful import, and a one-time quota.warning webhook at exactly 80% usage.
  • Crash-safe and idempotent. The worker claims jobs atomically (SELECT ... FOR UPDATE SKIP LOCKED), uses bounded attempts with exponential backoff, and resumes from the imported + failed offset after a crash, so a restart never double-imports.
  • Hard ceiling. A single batch accepts at most 500 items.

Related

  • Batch status, poll GET /v1/batch/{job_id} for progress and per-item errors.
  • Add a memory, the single-item write each batch item runs through.
  • SDK, the typed client surface.