API documentation
Integrate EqualDoX into your own systems: upload a PDF, poll the status, download the accessible PDF and its diagnostics.
Overview
The REST API v1 automates what you know from the web interface: you send a PDF, EqualDoX remediates it for accessibility asynchronously, and you download the result together with structured diagnostics.
The API is available to organisation accounts. Every request belongs to one person and one group of your organisation. The rules of the web interface apply: the same upload checks, the same page quotas and prices, the same retention. API jobs appear in the dashboard under the person and group that submitted them.
- JSON over HTTPS, the PDF as the request body
- Asynchronous: poll the status, no webhooks
- Diagnostics per job: outcome, pages, findings
- Safe retries with an
Idempotency-Key - Page usage of web interface and API together
Authentication
Create a key in the dashboard under Account › API keys: one for each group in which you may submit PDFs. The key is shown only once, so store it securely.
- Base URL
https://equaldox.de/api/v1- Header
Authorization: Bearer eqx_…
curl -sS --fail-with-body https://equaldox.de/api/v1/usage \
-H "Authorization: Bearer $EQUALDOX_API_KEY"
Key rules
- A key belongs to you and one group: jobs are submitted under that group, and the key sees only your jobs in it. For another group, use that group's key.
- Regenerating or revoking a key takes effect immediately. Each person can create at most five new keys within 24 hours.
- A key stops working when your membership ends, you leave the group or the organisation is no longer active.
- Use the key on your server only, never in browser code, apps or repositories. Calls from web pages on other domains are not supported.
- Accept new terms of service in the dashboard first; until then the API answers
403.
Quickstart
Processing is asynchronous: the upload creates a job, which you poll until job.status is DONE or FAILED. Do not wait for diagnostics.outcome.final; it only shows whether the diagnostics can still change.
#!/usr/bin/env bash
# Requires curl 7.76+ and jq; first: export EQUALDOX_API_KEY="eqx_…"
set -euo pipefail
BASE="https://equaldox.de/api/v1"
AUTH="Authorization: Bearer $EQUALDOX_API_KEY"
FILE="annual-report-2026.pdf"
IDEM_KEY="annual-report-2026-$(date +%Y%m%d%H%M%S)" # your own ID for this upload
NAME=$(jq -rn --arg f "$(basename "$FILE")" '$f|@uri') # percent-encode the file name
# 1. Upload; after a lost connection, repeat the same request with the same IDEM_KEY
JOB=$(curl -sS --fail-with-body -X POST "$BASE/jobs" -H "$AUTH" \
-H "Content-Type: application/pdf" \
-H "X-Upload-Filename: $NAME" \
-H "Idempotency-Key: $IDEM_KEY" \
--data-binary "@$FILE") || { echo "$JOB" >&2; exit 1; }
JOB_ID=$(jq -r '.job.id' <<< "$JOB")
# 2. Poll until job.status is DONE or FAILED
while :; do
JOB=$(curl -sS --fail-with-body "$BASE/jobs/$JOB_ID" -H "$AUTH") || { echo "$JOB" >&2; exit 1; }
STATUS=$(jq -r '.job.status' <<< "$JOB")
echo "Status: $STATUS"
case "$STATUS" in DONE|FAILED) break ;; esac
sleep 10
done
# 3. Download the result (--fail never writes an error response into the file)
if [ "$(jq -r '.job.result_available' <<< "$JOB")" = true ]; then
curl -sS --fail -o "${FILE%.pdf}_accessible.pdf" "$BASE/jobs/$JOB_ID/result" -H "$AUTH"
else
jq '.job.diagnostics.failure' <<< "$JOB" # FAILED: error_code and action
fi
# 4. Optional: delete the job and its documents now (otherwise after 7 days)
curl -sS --fail-with-body -X DELETE "$BASE/jobs/$JOB_ID" -H "$AUTH"
- 1. Upload The PDF as the request body, the file name percent-encoded in
X-Upload-Filename(ending in.pdf). - 2. Poll Every 10 seconds; 60 requests per minute and person are allowed.
- 3. Download Only with
result_available: true;--failnever saves an error response as a PDF. - 4. Delete Optional; otherwise automatically 7 days after upload.
API reference
All paths are relative to https://equaldox.de. Responses are JSON with "status": "ok", except the PDF download. All fields and schemas are described in the OpenAPI 3.1 specification (JSON).
| Endpoint | Purpose | Key parameters | Response |
|---|---|---|---|
POST /api/v1/jobs |
Upload a PDF, start the conversion | Body: PDF; headers Content-Type, X-Upload-Filename, optional Idempotency-Key |
201 job (repeat 200) |
GET /api/v1/jobs |
List jobs, newest first | limit 1–100 (default 50), offset |
jobs, total |
GET /api/v1/jobs/{id} |
Status, pages, billing, diagnostics summary | none | job |
GET /api/v1/jobs/{id}/diagnostics |
Diagnostics with findings per page | none | job_id, diagnostics |
GET /api/v1/jobs/{id}/result |
Download the accessible PDF | none | application/pdf |
DELETE /api/v1/jobs/{id} |
Delete the job and its documents | none | job_id, deleted |
GET /api/v1/usage |
Charged pages per period | from, to (YYYY-MM-DD, both or neither; default: current month) |
usage |
A key sees only your own jobs in its group, including those you uploaded there in the web interface; any other job answers 404. Timestamps are UTC in ISO 8601 format.
GET /api/v1/jobs/{id} (shortened){
"status": "ok",
"job": {
"id": "3f6c2a1e-8b0d-4c55-9a77-1d2e3f4a5b6c",
"status": "DONE",
"filename": "annual-report-2026.pdf",
"page_count": 24,
"expires_at": "2026-11-16T09:00:00Z",
"result_available": true,
"error_code": null,
"billing": {"pages_reserved": 24, "pages_charged": 24,
"settled": true, "failed_pages": []},
"links": {"result": "/api/v1/jobs/3f6c2a1e-…/result"},
"diagnostics": {
"outcome": {"state": "succeeded", "final": true},
"pages": {"total": 24, "converted": 24, "failed": []},
"failure": null
}
}
}
Key job fields
statusUPLOADED,PROCESSING,DONEorFAILEDresult_available,links.result- The PDF can be downloaded
expires_at- When the documents are deleted automatically
error_code- Reason for
FAILED billing- Reserved and charged pages
diagnostics- Diagnostics summary, only in
GET /api/v1/jobs/{id}
Important integration details
-
File format and size
PDF only, up to 50 MB (52,428,800 bytes), as the request body with
Content-Type: application/pdf. File name percent-encoded inX-Upload-Filename, ending in.pdf, at most 255 characters. Empty, damaged and password-protected PDFs:422. -
Rate limit
60 requests per minute per person, across all keys. Above that:
429withRetry-After(seconds); wait that long, then repeat. Poll single jobs at most every 5 seconds, many jobs together viaGET /api/v1/jobs. -
Idempotency and retries
Send your own
Idempotency-Keywith each upload (1–255 visible ASCII characters). The identical repeat returns the same job (200,Idempotency-Replayed: true), with no second charge. Valid for 24 hours per person; another file or name:409. AfterFAILED, use a new key. -
Status and result
UPLOADED,PROCESSING, then finallyDONEorFAILED. The PDF is ready as soon asresult_availableistrue. The API delivers the remediated PDF; a version corrected later in the inspection view is available in the dashboard. -
Retention and deletion
Automatic deletion 7 days after upload (
expires_at), then404.DELETEremoves a job earlier, also while it is being processed; then no pages are charged. Extension to 30 days in the dashboard. -
Page quota and billing
Your organisation's quota and prices, as in the web interface, with no API surcharge. Pages are reserved on upload and charged when the job finishes, failed pages and
FAILEDjobs not. Not enough pages:409. Usage per day:GET /api/v1/usage.
Diagnostics
Every job carries a summary in diagnostics: outcome (overall result), pages (total, converted, failed) and, for FAILED, failure with action. GET …/diagnostics adds the individual findings: errors, warnings and notes with page and code.
The findings come from the automatic check of the remediated PDF, which the inspection view in the dashboard shows as well. EqualDoX uses its own accessibility validator for it. The validator is designed to detect all accessibility violations that veraPDF and PAC can detect. The diagnostics are a technical check result, not a certification and not a legal assessment.
Values of outcome.state
pending- The job is still being processed
checking- Converted; the check is still running
succeeded- Converted without reported errors or warnings
succeeded_with_warnings- Converted; review the warnings
review_required- At least one error; review it in the inspection view
failed- Conversion failed; see
failure.action
outcome.final only shows whether the diagnostics can still change. Whether a job is finished is decided by job.status.
Error handling
Errors are JSON: {"status": "error", "error": "<code>"}, for invalid input also fields with field and reason. Repeat a request unchanged only after idempotency_request_in_progress, 429 and 5xx; all other errors need a changed request or an action in the dashboard.
| Status | Error codes | What to do |
|---|---|---|
| 401 | api_key_required, invalid_api_key |
Send exactly one Authorization: Bearer … header. Key invalid, revoked or regenerated: create a new one in the dashboard. |
| 403 | terms_acceptance_required, processing_restricted |
Accept the new terms of service in the dashboard. If processing is restricted, contact us. |
| 404 | not_found, result_not_available |
Job unknown, deleted, expired or not visible. No result: wait for DONE; FAILED has none. |
| 405, 413, 415, 422 | method_not_allowed, payload_too_large, unsupported_media_type, validation_failed |
Fix the request. For 422, fields names the reason, e.g. file: password_protected or filename: not_pdf_extension. |
| 409 | page_quota_exceeded, member_page_limit_exceeded |
Not enough pages (pages_required, pages_remaining): buy pages or ask your organisation's administrators. |
| 409 | dpa_required, dpa_update_required, organization_not_active, upload_group_unavailable |
Account not ready for uploads: accept the data processing agreement (DPA) or its update in the dashboard, check the organisation and group. |
| 409 | idempotency_key_reused, idempotency_request_in_progress |
Key used for another request: use a new one. First request still running: repeat after Retry-After. |
| 429 | rate_limited |
Wait Retry-After seconds, then repeat. |
| 500, 503 | server_error, processing_unavailable, storage_unavailable, storage_locked, uploads_disabled |
Temporary: repeat later with growing intervals, uploads with the same Idempotency-Key. |
A failed conversion is not an HTTP error: the job ends with FAILED, and diagnostics.failure.action says what to do: retry_later (upload again later with a new Idempotency-Key), fix_input (the file is not a usable PDF), contact_support (contact us) or resubmit (submit again). FAILED jobs are not charged.
Want to integrate EqualDoX into your workflows?
With an organisation account you create your API key in the dashboard. We are happy to help with questions about the integration.