Authentication
Every request to the public API must include an X-API-Key header carrying a personal API key. Keys are created and revoked from the Settings โ API Keys tab. API key creation requires the Starterplan or higher โ free-trial accounts can view the tab but must upgrade before issuing their first key.
Keys are prefixed with wga_ followed by 32 hexadecimal characters. The full secret is shown once at creation time โ store it in a secrets manager or environment variable, never in source control.
curl https://www.ellon.ai/api/v1/subscriptions/me \
-H "X-API-Key: $ELLON_API_KEY"Scope:v1 keys inherit the full permissions of the owning user and have no scoping โ treat every key as if it could read or mutate any resource in the account. Scoped keys are on the roadmap.
Rate limits
Rate limits are applied per API key and vary by subscription tier. Each response carries the standard slowapi throttling headers so clients can self-regulate:
X-RateLimit-Limitโ The active quota for the current windowX-RateLimit-Remainingโ Requests remaining before throttling kicks inX-RateLimit-Resetโ Unix timestamp when the window resetsRetry-Afterโ Seconds to wait after a 429 response
| Plan | Tier key | Per minute | Per hour |
|---|---|---|---|
| Free Trial | free_trial | 10 | 100 |
| Starter | starter | 30 | 1,000 |
| Professional | professional | 60 | 3,000 |
| Business | business | 120 | 10,000 |
When a key exceeds its window, the API returns 429 Too Many Requests with error code rate_limit_exceeded. Rate limits are a burst-protection mechanism and are separate from monthly plan usage caps (see Plan enforcement below).
Plan enforcement
The public API is metered against the same monthly allowances (pages, files, characters) as the web application. Translation, redaction, compare, and clause-analysis requests are billed against your subscription tier or consume available credits exactly as they do in the UI.
When a request would exceed the plan allowance, the API returns 429 Too Many Requests with error code plan_limit_exceeded and a structured details object containing the feature name, the usage so far, and the configured limit:
{
"error": {
"code": "plan_limit_exceeded",
"message": "Monthly translation page limit reached. Used 1200/1000 pages this billing period.",
"details": {
"feature": "translation",
"used": 1200,
"limit": 1000
}
}
}See Pricing for the per-tier allowances, or call GET /api/v1/subscriptions/usage programmatically to check your current utilization.
Errors
Every error returned by the public API uses the same envelope, regardless of which endpoint or middleware produced it:
{
"error": {
"code": "<stable_identifier>",
"message": "<human-readable message>",
"details": <optional object with structured info>
}
}error.code is a stable string you can branch on. The list of codes the public API emits today:
| Code | HTTP | Meaning |
|---|---|---|
bad_request | 400 | Malformed request |
unauthorized | 401 | Missing or invalid API key |
forbidden | 403 | Key is valid but not allowed for this resource |
not_found | 404 | Resource does not exist |
method_not_allowed | 405 | HTTP verb not supported on this path |
conflict | 409 | Resource state conflict |
payload_too_large | 413 | Upload or body exceeds size limit |
unsupported_media_type | 415 | Content-Type not accepted |
validation_error | 422 | Request body failed schema validation |
rate_limit_exceeded | 429 | Per-key request rate exceeded |
plan_limit_exceeded | 429 | Monthly plan allowance exceeded for this feature |
internal_error | 500 | Unhandled server error |
bad_gateway | 502 | Upstream dependency failed |
service_unavailable | 503 | Service temporarily unavailable |
gateway_timeout | 504 | Upstream dependency timed out |
Note: rate_limit_exceeded and plan_limit_exceeded both return HTTP 429, but they mean different things. Rate-limit errors indicate burst abuse and will clear within seconds; plan-limit errors indicate the account has consumed its monthly allowance and will not clear until the next billing cycle or a plan upgrade.
Example: resource not found.
{
"error": {
"code": "not_found",
"message": "Redaction job not found.",
"details": null
}
}Example: validation failure with per-field detail.
{
"error": {
"code": "validation_error",
"message": "Request validation failed",
"details": {
"errors": [
{
"type": "missing",
"loc": ["body", "document_id"],
"msg": "Field required",
"input": null
}
]
}
}
}Endpoints: Documents
Upload a document before running a translation, redaction, compare, or analysis operation. Documents are the primary input resource for every processing feature in the API.
| POST | /documents/upload | Upload a document: DOCX, PDF, DOC, PPTX, IDML, MD, or TEX file (multipart form). |
| GET | /documents/history | List uploaded documents for the authenticated user. |
| GET | /documents/{document_id} | Fetch metadata for a single document. |
| DELETE | /documents/{document_id} | Soft-delete a document and its derived files. |
curl https://www.ellon.ai/api/v1/documents/upload \
-H "X-API-Key: $ELLON_API_KEY" \
-F "file=@contract.pdf"Endpoints: Translation jobs
Translate a previously-uploaded document into any supported target language. Jobs run asynchronously โ create, poll for completion, then download the translated result.
| POST | /translation-jobs | Create a translation job. |
| POST | /translation-jobs/estimate | Estimate token cost before committing. |
| GET | /translation-jobs | List translation jobs. |
| GET | /translation-jobs/{job_id} | Poll job status and progress. |
| GET | /translation-jobs/{job_id}/download | Download the translated file. |
| GET | /translation-jobs/{job_id}/download-pdf | Download the translated file as PDF. |
| POST | /translation-jobs/{job_id}/stop | Halt a running job. |
| POST | /translation-jobs/{job_id}/resume | Resume a stopped job. |
| DELETE | /translation-jobs/{job_id} | Delete a job and its artifacts. |
# 1. Create the job
curl https://www.ellon.ai/api/v1/translation-jobs \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"document_id": "8f1c9d42-4b6e-4c8a-9f3d-1e2a7b6c5d4f",
"target_language": "fr",
"output_format": "single",
"column_to_keep": "translated"
}'
# 2. Poll status until "status": "completed"
curl https://www.ellon.ai/api/v1/translation-jobs/$JOB_ID \
-H "X-API-Key: $ELLON_API_KEY"
# 3. Download the result
curl https://www.ellon.ai/api/v1/translation-jobs/$JOB_ID/download \
-H "X-API-Key: $ELLON_API_KEY" \
-o translated.docxEndpoints: Redaction jobs
Redaction is a multi-step state machine: detect PII, review the detected entities, confirm which ones to redact, then download the redacted output. The redaction_style field accepts blackbar, label, or pseudonym.
| POST | /redaction-jobs | Create a job and start PII detection. |
| GET | /redaction-jobs | List redaction jobs. |
| GET | /redaction-jobs/{job_id} | Poll detection status and fetch detected entities. |
| PATCH | /redaction-jobs/{job_id}/entities | Adjust which entities to include or exclude. |
| POST | /redaction-jobs/{job_id}/confirm | Confirm entity selection and begin redaction. |
| GET | /redaction-jobs/{job_id}/download | Download the redacted document. |
| GET | /redaction-jobs/{job_id}/download-pdf | Download the redacted document as PDF. |
| GET | /redaction-jobs/{job_id}/redaction-log | Download the audit log of what was redacted. |
| DELETE | /redaction-jobs/{job_id} | Delete a job and its artifacts. |
# 1. Kick off detection
curl https://www.ellon.ai/api/v1/redaction-jobs \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"document_id": "8f1c9d42-4b6e-4c8a-9f3d-1e2a7b6c5d4f",
"redaction_style": "blackbar",
"language": "en"
}'
# 2. Poll until detected_entities is populated
curl https://www.ellon.ai/api/v1/redaction-jobs/$JOB_ID \
-H "X-API-Key: $ELLON_API_KEY"
# 3. Confirm the selection and run the redaction
curl https://www.ellon.ai/api/v1/redaction-jobs/$JOB_ID/confirm \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"selected_entity_ids": ["e_1","e_2","e_3"]}'
# 4. Download the redacted file
curl https://www.ellon.ai/api/v1/redaction-jobs/$JOB_ID/download \
-H "X-API-Key: $ELLON_API_KEY" \
-o redacted.docxEndpoints: Compare jobs
Submit two documents (an original and a revised version) and receive a tracked-changes redline as output. Optionally enable semantic analysis to get an AI summary of the substantive differences.
| POST | /compare-jobs | Create a comparison between two documents. |
| GET | /compare-jobs | List compare jobs. |
| GET | /compare-jobs/{job_id} | Poll job status. |
| GET | /compare-jobs/{job_id}/download | Download the redlined document. |
| GET | /compare-jobs/{job_id}/download-pdf | Download the redlined document as PDF. |
| DELETE | /compare-jobs/{job_id} | Delete a job and its artifacts. |
curl https://www.ellon.ai/api/v1/compare-jobs \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"original_document_id": "8f1c9d42-4b6e-4c8a-9f3d-1e2a7b6c5d4f",
"revised_document_id": "2d7a8b93-1f4c-4a6d-b8e5-5c3f9a1d6e2b",
"enable_semantic_analysis": true
}'Endpoints: Clause analysis
Analyze a contract for clause-level risk, plain-language summaries, and missing-clause detection. Pass an optional jurisdiction and contract_type to tailor the analysis.
| POST | /analysis-jobs | Create a clause-analysis job. |
| GET | /analysis-jobs | List analysis jobs. |
| GET | /analysis-jobs/{job_id} | Poll job status and fetch structured results. |
| GET | /analysis-jobs/{job_id}/download | Download the raw JSON analysis payload. |
| GET | /analysis-jobs/{job_id}/download-pdf | Download a formatted PDF report. |
| DELETE | /analysis-jobs/{job_id} | Delete a job and its artifacts. |
curl https://www.ellon.ai/api/v1/analysis-jobs \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"document_id": "8f1c9d42-4b6e-4c8a-9f3d-1e2a7b6c5d4f",
"jurisdiction": "uk",
"contract_type": "nda",
"language": "en"
}'Endpoints: Affiliate outreach
Programmatic access to the affiliate outreach workspace. Requires the affiliate role on your account โ apply at /affiliate. Non-members receive 404 (not 403) on every route, so the surface stays invisible to the general user base.
Typical automation flow: create a campaign, bulk-add recipients, check quota, trigger generation, edit drafts, mark-contacted, archive. Drafts stay server-side so the same automation can resume across runs.
Campaigns
| GET | /outreach/campaigns | List your non-archived campaigns. |
| POST | /outreach/campaigns | Create a campaign with name + context. |
| GET | /outreach/campaigns/{id} | Full detail including recipients and drafts. |
| PATCH | /outreach/campaigns/{id} | Update name, context, or status. |
| DELETE | /outreach/campaigns/{id} | Archive a campaign (soft delete). |
Recipients
| POST | /outreach/campaigns/{id}/recipients | Bulk-add up to 500 recipients per campaign. |
| PATCH | /outreach/campaigns/{id}/recipients/{rid} | Update any recipient field. |
| DELETE | /outreach/campaigns/{id}/recipients/{rid} | Hard-delete a recipient and its draft. |
| POST | /outreach/campaigns/{id}/recipients/{rid}/mark-contacted | Flip status to contacted + record timestamp. |
Drafts & generation
| POST | /outreach/campaigns/{id}/generate | Run the LLM for ready recipients (10/min burst, daily quota). |
| PUT | /outreach/campaigns/{id}/recipients/{rid}/draft | Persist a manual edit to the draft. |
| GET | /outreach/quota | Today's quota snapshot (limit, used, remaining, reset). |
| POST | /outreach/check-status | Cross-campaign suppression check, scoped to caller. |
Example: end-to-end automation
# 1. Create a campaign
CAMPAIGN_ID=$(curl -s https://www.ellon.ai/api/v1/outreach/campaigns \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Q3 law firms โ DACH",
"context": {
"affiliate_link": "https://ellon.ai?ref=$YOUR_CODE",
"prospect_context": "Mid-size law firms in Germany with active translation pipelines",
"target_market": "Germany ยท DACH",
"target_role": "Partner ยท Managing Director",
"pain_points": "Slow turnaround on multi-language contract reviews",
"tone": "warm",
"language": "en",
"cta_style": "soft",
"email_length": "short"
}
}' | jq -r .id)
# 2. Pre-flight the suppression check (optional)
curl -s https://www.ellon.ai/api/v1/outreach/check-status \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"emails": ["anna@kanzlei-beispiel.de", "marc@law-example.de"]}'
# 3. Add recipients (server flags existing Ellon users as "protected")
curl -s "https://www.ellon.ai/api/v1/outreach/campaigns/$CAMPAIGN_ID/recipients" \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipients": [
{"email": "anna@kanzlei-beispiel.de", "first_name": "Anna", "company": "Kanzlei Beispiel"},
{"email": "marc@law-example.de", "first_name": "Marc", "company": "Law Example"}
]
}'
# 4. Check quota before spending tokens
curl -s https://www.ellon.ai/api/v1/outreach/quota \
-H "X-API-Key: $ELLON_API_KEY"
# 5. Generate drafts for every recipient with status="ready"
curl -s "https://www.ellon.ai/api/v1/outreach/campaigns/$CAMPAIGN_ID/generate" \
-H "X-API-Key: $ELLON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"recipient_ids": []}'
# 6. Mark a recipient as contacted after you send
curl -s -X POST \
"https://www.ellon.ai/api/v1/outreach/campaigns/$CAMPAIGN_ID/recipients/$RID/mark-contacted" \
-H "X-API-Key: $ELLON_API_KEY"Errors & guardrails
- 404on any route if you don't have the affiliate role, or on campaigns/recipients you don't own. Never 403 โ we deliberately hide the surface.
- 429 on
/generatewhen the daily quota would be exceeded. Response body carrieslimit,used,remaining,reset_at. A separate 10/min burst cap also applies. - 409 on bulk-add when a concurrent insert collides on the
(campaign_id, email)uniqueness โ rare, retriable. - Recipients with status
protected(existing Ellon customer) are server-set and can't be overridden via the API. They are silently skipped by/generate.
Endpoints: Credits & subscription
Read-only endpoints that expose the caller's current credit balance, recent transactions, active subscription, and monthly usage. These do not mutate billing state โ purchases and upgrades still happen in the web app.
| GET | /credits/balance | Current remaining credit balance. |
| GET | /credits/transactions | Recent credit debits and top-ups. |
| GET | /subscriptions/me | The authenticated user's active subscription. |
| GET | /subscriptions/tiers | Publicly available subscription tiers and pricing. |
| GET | /subscriptions/usage | Current-cycle usage vs. plan allowance. |
| GET | /subscriptions/usage/history | Historical usage by billing cycle. |
curl https://www.ellon.ai/api/v1/subscriptions/usage \
-H "X-API-Key: $ELLON_API_KEY"OpenAPI & SDKs
The full machine-readable OpenAPI 3 specification describes every public endpoint, every request and response schema, and every error code emitted by the API. Use it to generate a typed client in any language with openapi-generator, openapi-ts, or the tool of your choice.
- /api/public/openapi.json โ the raw OpenAPI schema (JSON).
- /api/public/docs โ an interactive ReDoc reference for browsing every endpoint.
# Example: generate a TypeScript client
npx @hey-api/openapi-ts \
--input https://www.ellon.ai/api/public/openapi.json \
--output ./src/ellon-clientChangelog
Initial public release. All document processing features โ translate, redact, compare, and analyze โ are available via API with a unified authentication, rate-limiting, and error envelope.