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.

Sending a token
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.

  1. POST /api/storage/presign-upload with the file's content type, extension and exact byte size. You get back { key, url }. Send the tool field too: it moves an over-size rejection ahead of the upload instead of after it.
  2. PUT the file bytes to url. This is a direct upload to S3; no Authorization header.
  3. POST the tool endpoint with { "keys": [key], "options": { … } }. You get back a downloadUrl — a short-lived presigned URL for the result — and resultBytes.
Splitting pages 1–3 and 7 out of a PDF
# 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\"}}"
What step 3 returns
{
  "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.

An idempotent submission
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.

Tool-run ceilings per caller
TierPer minutePer hourPer day
Guest (no token)20200500
Signed in6010003000
Paid pass12020006000
Headers on a successful call
RateLimit-Limit: 20
RateLimit-Remaining: 19
RateLimit-Reset: 3
RateLimit-Policy: 20;w=60, 200;w=3600, 500;w=86400
Headers on a 429
HTTP/1.1 429 Too Many Requests
Retry-After: 4
RateLimit-Limit: 20
RateLimit-Remaining: 0
RateLimit-Reset: 4

Reads 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.

Error codes
CodeHTTPMeaning
BAD_REQUEST400The request body or an option value was not valid. The message names what to fix.
PASSWORD_REJECTED400The supplied PDF password was wrong. field is password.
SIGN_IN_REQUIRED401This endpoint or this tool needs an account. Obtain a bearer token and retry.
FORBIDDEN403Authenticated, but not allowed to perform this action.
OBJECT_FORBIDDEN403The object key named in keys belongs to another account.
NOT_FOUND404No endpoint at this path, or the named resource does not exist.
METHOD_NOT_ALLOWED405The path exists but not for this HTTP method. Allow lists the ones that work.
NOT_ACCEPTABLE406This API only produces application/json. Widen your Accept header.
PREMIUM_REQUIRED402The tool is available on a paid pass. See /pricing.
FILE_TOO_LARGE413The upload exceeds the caller's tier cap. Sign in or upgrade for a higher ceiling.
UNSUPPORTED_MEDIA_TYPE415Send Content-Type: application/json.
RATE_LIMITED429Too many requests. Wait Retry-After seconds; RateLimit-Reset says when the window refills.
AI_BUDGET_EXCEEDED429The caller's AI credit allowance for the period is spent.
SERVICE_BUSY503This instance is already running as much heavy work as it can. Retry after Retry-After.
AI_UNAVAILABLE503The upstream model provider failed. The request was not charged; retry.
PROCESSING_TIMEOUT504Processing started and was abandoned. Retrying the same file will time out again — send a smaller one.
PROCESSING_FAILED500Unexpected server fault. Quote requestId when reporting it.
The error envelope
{
  "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:

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