Before you start
A key with write
Ingest routes need the
write scope. Check yours with GET /v1/me.The base URL
https://api.get-exo.com, with your key in X-Exo-API-Key.A subject, if B2B2C
Writing on behalf of an end user means provisioning a subject first.
The shortest call that works
202 Accepted
Which route to use
All four return the same accept envelope and all four are polled the same way.
The full loop
Send the content
Post to the route that matches your input. Add an
Idempotency-Key header on POST /v1/ingest and POST /v1/ingest/batch so a network retry cannot create a second copy.metadata is a free-form object. It is stored with the content and comes back on graph reads, so use it for your own foreign keys.Poll the job
GET /v1/ingest/{jobId}/status reports the current phase and the phases already done.200 OK
errorMessage is non-null only when status is failed.Read what it created
GET /v1/jobs/{jobId} returns the finished job with a result block. This is the part worth logging: it tells you what your content became, not just that it uploaded.200 OK
result itself is null until the job reaches a terminal status.Batching
POST /v1/ingest/batch takes up to 500 items. Each item is an object with a required content of up to 100,000 characters, plus optional title, source_type and metadata. Every valid item becomes its own job, so one slow or failing item cannot hold up the rest.
202 Accepted
metadata is not an object, comes back in results as {"status": "skipped", "reason": "..."} and is counted in skipped. It never fails the batch. Read results in request order to find out which of your items did not make it.
failed is total minus succeeded, so skipped items are counted in both skipped and failed. Use skipped when you want to know how many items were rejected before enqueue.Files and transcripts
POST /v1/import takes one file as multipart/form-data under the field name file.
POST /v1/import/transcript adds one required form field, target_speaker. Only that speaker’s turns land in the subject’s graph, which is what you want when three people are in the room and only one of them is the subject.
GET /v1/import lists the 20 most recent imports for the current subject, newest first. nodesCreated and domainsDetected stay null until the worker finishes.
200 OK
Retries that do not duplicate
Send anIdempotency-Key header on POST /v1/ingest and POST /v1/ingest/batch. A retry with the same key and the same body returns the original job id rather than queueing a second copy. That makes the accept safe to retry on a timeout, a 429 or a 503, which are exactly the moments you do not know whether the first attempt landed.
Writing on behalf of a subject
By default every ingest is written to the API key owner’s partition. To write to an end user’s partition instead, provision the subject once and then send theX-Exo-Subject header on the ingest call.
Canceling
POST /v1/jobs/{jobId}/cancel cancels a job that is still pending. A job the worker has already claimed cannot be canceled: cancellation never interrupts in-flight work.
When it goes wrong
Next
Retrieving context
Read the graph back, and understand
path, degraded and the null cognition.Reacting to change
Stop polling. Subscribe to
job.completed over SSE or a webhook.