The Elie API
Elie has a partner API: your own software can send Elie work and collect the outcome, with no browser and no signed-in person. It covers the data only: send a document, a recording or a question, watch its status, take the result, and act on what you sent. Configuration (creating orchestrators or knowledge bases, connecting sources, changing access) stays in the workspace, and no key can unlock it.
Available today:
- IntELIEDocs, under
/external/v1/inteliedoc/: upload a document into an existing orchestrator, poll its status, take the extracted fields, correct, review, re-run or delete it. - Knowledge Base, under
/external/v1/kb/: add a document to an existing knowledge base, ask questions, retrieve passages, hold a conversation and set per-document access. - Voice IntELIEgence, under
/external/v1/voice/: send a recording to an existing voice application, poll its status, and take the transcript and outputs. - IntELIEKonnect, under
/external/v1/konnect/: read and manage the bindings that route your connectors to their targets.
Each page lists every endpoint with the scope it needs.
The Knowledge Base chat widget for web pages is separate. It uses a short-lived widget token issued by a signed-in person, not an API key: see Knowledge Base widget.
Your base URL
Take your workspace's address and replace tenant with api: a workspace at
https://tenant.example.com has its API at https://api.example.com, the address the examples
on these pages use. Every partner path starts /external/v1/.
Credentials: an API key, exchanged for a 15-minute pass
An administrator creates keys under Developers in the workspace: see
Managing API keys. A key looks like elie_sk_live_... (or
elie_sk_test_... for a test key), is shown once, and Elie keeps only a hash of it, so it can
never be displayed again. If one is lost or leaks, Regenerate it: the replacement keeps the
old key's scopes and reach, so you change one line of configuration.
You set an expiry when you create a key, and it can be no more than a year away. After it, the token exchange refuses the key and an unattended integration stops, with nothing in your own logs to explain why. Put the date in your calendar and regenerate the key before it arrives. A regenerated key expires a year from the day you regenerate it.
Your server swaps the key for a short-lived pass, and swaps again when the pass runs out:
curl -s -X POST $BASE/external/v1/auth/token \
-H 'Content-Type: application/json' \
-d '{"grant_type":"api_key","api_key":"elie_sk_live_..."}'
# {"access_token":"...","token_type":"Bearer","expires_in":900}
Send the pass as Authorization: Bearer <access_token> on every call. The exchange answers in
plain JSON, not in the data envelope the other endpoints use. A wrong grant_type is a 400,
an unknown, revoked or expired key is a 401 invalid_token, and more than 30 exchanges a minute
for one key is a 429 with Retry-After.
Three things to design around:
- Revocation takes up to 15 minutes to bite. Revoking a key stops new exchanges at once; a pass already issued keeps working until it expires, at most 900 seconds later.
- A key belongs to an integration, not to a person. It can do what its scopes allow, on the resources it is allowed to reach, within your organisation's plan. Who created it makes no difference, so it keeps working when that person's role changes or they leave.
- 403 and 404 mean different things.
403 authz_deniedmeans "you may not do this" and names the missing scope.404 not_foundmeans "there is nothing here for you": a resource outside your key's reach and one that does not exist answer the same way, on purpose. Check the key's Reach in the workspace.
Scopes
An administrator grants scopes per key. Ask only for what the integration needs.
IntELIEDocs: documents:read · documents:write · documents:delete · documents:rerun
(each re-run is charged) · documents:review · extractions:read · workqueues:read
Knowledge Base: kb:read · kb:query · kb:write · kb:delete
Voice IntELIEgence: voice:read · voice:write
IntELIEKonnect: konnect:bindings:read · konnect:bindings:write
Two more can be ticked on a key, jobs:read and identity:read, but no endpoint reads them yet,
so granting either changes nothing. Job status is already part of the document status you poll.
Requests and responses
A success is {"data": ..., "meta": {"correlation_id", "version", "next_cursor"}}, with any
empty part left out. An error is
{"error": {"code", "message", "details", "correlation_id", "retryable"}}, in snake_case, with
the code from a fixed list: invalid_token, authz_denied, not_found, schema_invalid,
rate_limited, billing_denied, idempotency_key_reused, conflict, file_too_large,
invalid_mime, internal_error. An IntELIEDocs upload adds two of its own, described on
its page. Quote meta.correlation_id when you contact support.
- Lists page with an opaque cursor. Pass
after=<meta.next_cursor>, and stop whennext_cursoris missing.limittakes 1-200; keep it the same for every page of one listing, or the call is refused. - Safe retries. Send an
Idempotency-Keyheader on writes. The same key with the same request replays the original response, markedIdempotency-Replayed: true; with a different request it is refused with409 idempotency_key_reused. A retry that arrives while the first call is still running gets409 conflictwithRetry-After. Only successful responses are kept, for 24 hours, so a failed call can be retried with the same key. - Downloads never redirect. A link to a file comes back in the response body with a
200, never as a302. Exports are the exception: they return the file itself.
Rate limits
Every call counts against one of three budgets, per key and per account, judged by its HTTP method so that a runaway status loop can never starve your uploads:
| Budget | Calls | Limit |
|---|---|---|
| reads | every GET except exports | 100 a second |
| writes | every POST, PUT, PATCH and DELETE, including knowledge base questions and conversation turns | 10 a second |
| exports | single and bulk IntELIEDocs exports | 2 a second |
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over
budget, you get 429 rate_limited with Retry-After; wait that long and you will converge.
Poll a document every 2 seconds for the first minute, then every 10 seconds.
Worked example: a document, end to end
BASE=https://api.example.com # your base URL, see above
AUTH="Authorization: Bearer $ACCESS_TOKEN" # from the exchange above
# where may this key send? (id and name only)
curl -s $BASE/external/v1/inteliedoc/workqueues -H "$AUTH"
# send a document (multipart, 25 MB at most; Idempotency-Key makes retries safe)
curl -s -X POST $BASE/external/v1/inteliedoc/workqueues/$WQ/documents \
-H "$AUTH" -H "Idempotency-Key: inv-2026-0042" \
-F "file=@invoice.pdf"
# 202 {"data":{"document_id":"...","job_id":"...","status":"received","status_url":"..."}}
# Retrying with the SAME Idempotency-Key replays this response: no second document and no
# second charge. Without the header, every send is a new document.
# poll
curl -s $BASE/external/v1/inteliedoc/documents/$DOC -H "$AUTH"
# collect (409 means not ready yet)
curl -s $BASE/external/v1/inteliedoc/documents/$DOC/result -H "$AUTH"
# the original file, as a link in the body
curl -s $BASE/external/v1/inteliedoc/documents/$DOC/content -H "$AUTH"
The same page covers exports (?format=csv|xlsx|json, up to 50 documents in bulk), deletion,
corrections (PATCH .../fields, then POST ...:review to make them stick) and
POST ...:rerun?version=active to run a document again without uploading it. A re-run
discards the previous result and every correction, so correct after re-running, never before.
Billing
Work done through the API is charged exactly as it is in the workspace, and Elie checks your
credit before it starts: with none left the call answers 402 billing_denied and nothing runs.
- IntELIEDocs charges per page once processing reaches review or completion. A run that fails is not charged. A re-run is charged when you start it.
- Knowledge Base charges an ingest per page, and each question, retrieval or conversation turn as one request once it is answered.
- Voice IntELIEgence charges per minute of audio, measured once the recording is transcribed. A conversation that fails is not charged.
API calls themselves are counted but not priced.
Field-level request and response schemas are in the workspace: open Developers, then API explorer. Its API reference is generated from the live services, and you can send test requests from it. This public page is the capability reference.