Developers
NexaPDF AI API Documentation
REST API for the NexaPDF AI PDF toolkit: authentication, endpoints, rate-limit headers, error codes and a machine-readable OpenAPI specification.
Base URL https://api.nexapdfai.com
Overview
The NexaPDF AI API is a JSON-over-HTTPS API at https://api.nexapdfai.com. It exposes the same 33 PDF tools the website runs on — merge, split, compress, convert, OCR, sign, redact — plus an AI layer for summarising, translating, chatting with and converting documents to Markdown.
The complete surface is published as an OpenAPI 3.1 document at `/openapi.json` and `/openapi.yaml`. Generate a client from it rather than hand-writing one; this page explains the parts a generator cannot express.
Every page on this site is also available as Markdown: send Accept: text/markdown and you get the prose without the layout. Responses carry Vary: Accept, so caches keep the two variants apart.
Authentication
Authentication is optional. Every tool endpoint works without an account; anonymous callers are identified by IP and metered accordingly. This is deliberate — the product does not put a sign-in wall in front of its tools, and neither does its API.
A bearer token raises the ceilings (rate limits and maximum upload size) and unlocks the account-owned resources — saved documents, subscriptions, signing history — which are not described in the public specification.
Tokens are AWS Cognito ID tokens obtained through the website's sign-in flow. There is no self-service API-key issuance today; if you need machine credentials for a server-side integration, ask at https://www.nexapdfai.com/contact.
Authorization: Bearer <cognito-id-token>Running a tool
Every tool run is three steps. File bytes never pass through the API — they go straight to object storage over a presigned URL, and the tool call names the resulting key.
POST /api/storage/presign-uploadwith the file's content type, extension and exact byte size. You get back{ key, url }. Send thetoolfield too: it moves an over-size rejection ahead of the upload instead of after it.PUTthe file bytes tourl. This is a direct upload to S3; noAuthorizationheader.POSTthe tool endpoint with{ "keys": [key], "options": { … } }. You get back adownloadUrl— a short-lived presigned URL for the result — andresultBytes.
# 1. ask for somewhere to put the file
PRESIGN=$(curl -sS -X POST https://api.nexapdfai.com/api/storage/presign-upload \
-H "Content-Type: application/json" \
-d '{"contentType":"application/pdf","extension":"pdf","sizeBytes":482113,"tool":"split-pdf"}')
KEY=$(echo "$PRESIGN" | jq -r .key)
URL=$(echo "$PRESIGN" | jq -r .url)
# 2. upload the bytes straight to storage
curl -sS -X PUT --upload-file report.pdf -H "Content-Type: application/pdf" "$URL"
# 3. run the tool
curl -sS -X POST https://api.nexapdfai.com/api/pdf/split-pdf \
-H "Content-Type: application/json" \
-d "{\"keys\":[\"$KEY\"],\"options\":{\"ranges\":\"1-3,7\"}}"{
"downloadUrl": "https://nexapdf-files-mum.s3.ap-south-1.amazonaws.com/results/…",
"resultBytes": 194233
}Endpoints
Synchronous PDF tools are POST https://api.nexapdfai.com/api/pdf/{tool}, where {tool} is one of: merge-pdf, split-pdf, rotate-pdf, watermark-pdf, protect-pdf, unlock-pdf, jpg-to-pdf, compress-pdf, organize-pdf, page-numbers, crop-pdf, repair-pdf, pdf-to-jpg, ocr-pdf, scan-to-pdf, compare-pdf, redact-pdf, pdf-forms, pdf-to-pdfa, sign-pdf, edit-pdf, word-to-pdf, excel-to-pdf, powerpoint-to-pdf, html-to-pdf, pdf-to-word, pdf-to-excel, pdf-to-powerpoint.
AI operations are POST https://api.nexapdfai.com/api/ai/{operation} for summarize, translate, markdown, chat. These are metered in credits as well as by rate, and a 503 AI_UNAVAILABLE means the model provider failed and the credit was refunded — retrying is correct.
Long-running work (OCR, heavy compression) can be submitted asynchronously to POST /api/jobs and polled at GET /api/jobs/{id} until status is DONE or FAILED. Polling is counted in the plumbing bucket below, so it never spends a tool allowance.
The tool slug in the path is the same slug the tool's page uses on the website, so https://www.nexapdfai.com/merge-pdf documents what POST /api/pdf/merge-pdf does.
Retrying safely
Send an Idempotency-Key header with any tool run or job submission. A replay carrying the same key returns the original result instead of doing — and charging for — the work again. This is what makes a retry after a network timeout safe, and it is the recommended default for any unattended client.
POST /api/jobs HTTP/1.1
Host: api.nexapdfai.com
Content-Type: application/json
Idempotency-Key: 5f2d1c40-3a1b-4a55-9c0e-1d2e3f4a5b6c
{"tool":"compress-pdf","keys":["uploads/….pdf"],"options":{"level":"strong"}}Rate limits
Every API response carries the standard RateLimit-* header family. Throttle against those rather than a fixed delay — they are the only place the current allowance is published, and they are correct at the moment you read them.
RateLimit-Limit is the tightest enforced window's ceiling, RateLimit-Remaining what is left in it, and RateLimit-Reset the seconds until the allowance is back to full. RateLimit-Policy lists every window at once, so a client pacing itself against the per-minute figure can still see the daily cap coming. A 429 additionally carries Retry-After, in seconds.
Refill is continuous rather than on a calendar boundary: the allowance trickles back, so waiting genuinely works and there is no cliff at the top of the hour.
| Tier | Per minute | Per hour | Per day |
|---|---|---|---|
Guest (no token) | 20 | 200 | 500 |
Signed in | 60 | 1000 | 3000 |
Paid pass | 120 | 2000 | 6000 |
RateLimit-Limit: 20
RateLimit-Remaining: 19
RateLimit-Reset: 3
RateLimit-Policy: 20;w=60, 200;w=3600, 500;w=86400HTTP/1.1 429 Too Many Requests
Retry-After: 4
RateLimit-Limit: 20
RateLimit-Remaining: 0
RateLimit-Reset: 4Reads that are not tool runs
Presign calls, job polling, pricing and configuration reads are counted in a separate, more generous bucket — 60 requests a minute for guests, 120 signed in, 240 on a paid pass. Browsing never spends a tool allowance, so polling a job aggressively costs you nothing except requests in this bucket.
Errors
Every failure — including the ones produced by the authentication layer before a request reaches a handler — is JSON with the same shape. Branch on code, show message to a person, and quote requestId in any bug report: it is what makes one response findable in the logs.
| Code | HTTP | Meaning |
|---|---|---|
BAD_REQUEST | 400 | The request body or an option value was not valid. The message names what to fix. |
PASSWORD_REJECTED | 400 | The supplied PDF password was wrong. field is password. |
SIGN_IN_REQUIRED | 401 | This endpoint or this tool needs an account. Obtain a bearer token and retry. |
FORBIDDEN | 403 | Authenticated, but not allowed to perform this action. |
OBJECT_FORBIDDEN | 403 | The object key named in keys belongs to another account. |
NOT_FOUND | 404 | No endpoint at this path, or the named resource does not exist. |
METHOD_NOT_ALLOWED | 405 | The path exists but not for this HTTP method. Allow lists the ones that work. |
NOT_ACCEPTABLE | 406 | This API only produces application/json. Widen your Accept header. |
PREMIUM_REQUIRED | 402 | The tool is available on a paid pass. See /pricing. |
FILE_TOO_LARGE | 413 | The upload exceeds the caller's tier cap. Sign in or upgrade for a higher ceiling. |
UNSUPPORTED_MEDIA_TYPE | 415 | Send Content-Type: application/json. |
RATE_LIMITED | 429 | Too many requests. Wait Retry-After seconds; RateLimit-Reset says when the window refills. |
AI_BUDGET_EXCEEDED | 429 | The caller's AI credit allowance for the period is spent. |
SERVICE_BUSY | 503 | This instance is already running as much heavy work as it can. Retry after Retry-After. |
AI_UNAVAILABLE | 503 | The upstream model provider failed. The request was not charged; retry. |
PROCESSING_TIMEOUT | 504 | Processing started and was abandoned. Retrying the same file will time out again — send a smaller one. |
PROCESSING_FAILED | 500 | Unexpected server fault. Quote requestId when reporting it. |
{
"code": "FILE_TOO_LARGE",
"message": "That file is 42 MB. Guests can upload up to 10 MB — sign in for 25 MB.",
"requestId": "524b70c3a73a4961a5a08b36da303705"
}Files and privacy
Uploads and results are removed by a one-day storage rule, and are never used to train models. The details are on the security page.
A presigned downloadUrl is short-lived. Fetch the result promptly rather than storing the URL.
Machine-readable resources
Everything an automated client needs to discover this API, at stable URLs:
- OpenAPI specification (JSON) — OpenAPI 3.1. The full machine-readable API surface.
- OpenAPI specification (YAML) — The same document, YAML-serialised.
- API documentation — This page. Ask for text/markdown to get it as Markdown.
- llms.txt — Site index for language models, per the llms.txt convention.
- Sitemap — Every public URL on the site.
- Service health — Liveness of the API itself.
Support
Questions, bug reports and requests for machine credentials: https://www.nexapdfai.com/contact. Include the requestId from the failing response.
There is no versioning header today; the API is at v1 and breaking changes would ship at a new path. Error code values are append-only — an existing one will not change meaning.
Everything at a stable URL
- OpenAPI specification (JSON) — OpenAPI 3.1. The full machine-readable API surface.
- OpenAPI specification (YAML) — The same document, YAML-serialised.
- API documentation — This page. Ask for text/markdown to get it as Markdown.
- llms.txt — Site index for language models, per the llms.txt convention.
- Sitemap — Every public URL on the site.
- Service health — Liveness of the API itself.