API Reference
Complete reference for every PDFPipe endpoint, including request parameters, response schemas, authentication, and error handling.
Base URL
All API requests are made to:
https://api.pdfpipe.dev/v1HTTPS is required for all requests. HTTP connections are rejected.
Authentication
Authenticate by including your API key in the Authorization header:
Authorization: Bearer pk_live_...API keys are created in the Dashboard. Each key can optionally be restricted to specific IP addresses. Keys start with pk_live_ and are shown only once at creation.
Convert a PDF
/v1/convertConvert a PDF from a URL into your chosen output format. Files under 10 MB are processed synchronously (200). Larger files, requests with async: true, or jobs that exceed your timeout window return a poll URL (202). Use returnMethod: "inline" to embed the converted payload in JSON when the response is synchronous (or on status when using ?returnMethod=inline).
Request body
| Parameter | Type | Description |
|---|---|---|
urlrequired | string | The HTTP or HTTPS URL of the PDF. Max 2048 characters. |
format | string | Output format. One of: json, text, markdown, xml, csv, base64, binary, png, jpg, webp. Default: json. |
type | string | Force PDF type detection. "inline" or "attachment". Omit to auto-detect. |
async | boolean | Force asynchronous processing. Default: false. |
returnMethod | string | How the result is delivered when complete: "file" (presigned resultUrl) or "inline" (content + contentType in the JSON body). Default: file. |
timeout | integer | Optional. Max seconds (1–60) to attempt synchronous processing before the job is queued. Omit for default behaviour. |
webhook | object | Optional. After async completion, POSTs the result to an HTTPS URL. Shape: { url: string, secret?: string }. If secret is omitted, one is generated and returned on the async response. Payloads are signed with HMAC-SHA256 (see Webhooks). |
Example request
{
"url": "https://example.com/report.pdf",
"format": "json",
"type": "inline",
"async": false,
"returnMethod": "file",
"timeout": 30,
"webhook": { "url": "https://example.com/hooks/pdfpipe" }
}Responses
With returnMethod: "inline", synchronous 200 responses include content, contentType, and for binary formats (png, jpg, webp, binary, base64) contentEncoding: "base64". If inline delivery exceeds size limits, the API may return a presigned URL instead and set returnMethodFallback: true with returnMethodFallbackReason.
{
"requestId": "req_01J9X7K2M...",
"status": "complete",
"format": "json",
"pagesProcessed": 3,
"creditsUsed": 1,
"resultUrl": "https://pdfpipe-results.s3...",
"expiresAt": "2026-02-23T12:00:00.000Z"
}{
"requestId": "req_01J9X7K2M...",
"status": "complete",
"format": "json",
"pagesProcessed": 3,
"creditsUsed": 1,
"returnMethod": "inline",
"contentType": "application/json",
"content": { "pages": [ { "page": 1, "text": "..." } ] },
"returnMethodFallback": false
}{
"requestId": "req_01J9X7K2M...",
"status": "pending",
"pollUrl": "/v1/status/req_01J9X7K2M..."
}{
"requestId": "req_01J9X7K2M...",
"status": "pending",
"pollUrl": "/v1/status/req_01J9X7K2M...",
"webhook": {
"url": "https://example.com/hooks/pdfpipe",
"secret": "whsec_generated_or_provided"
},
"message": "Example: job queued after synchronous processing exceeded your timeout (1–60s)."
}Webhooks
When you include webhook on a convert request that ends up asynchronous, PDFPipe POSTs to your HTTPS URL when processing finishes. The async 202 response includes webhook.url and webhook.secret (generated if you did not supply secret). Verify deliveries with HMAC-SHA256 over the raw request body using that secret; the request includes X-PDFPipe-Signature: sha256=<hex> (plus X-PDFPipe-Request-Id and X-PDFPipe-Event).
Batch Convert
/v1/convert/batchSubmit multiple PDF URLs for conversion in a single request. All jobs are processed asynchronously. The maximum batch size depends on your tier.
Request body
| Parameter | Type | Description |
|---|---|---|
urlsrequired | array | Array of URL objects. Each must have a url field. Optional per-item: format, type, pages, metadata, returnMethod, timeout, webhook. |
defaults | object | Default values applied to all URLs. Supports format, type, returnMethod, timeout, and webhook. |
Example
{
"urls": [
{ "url": "https://example.com/invoice-1.pdf" },
{ "url": "https://example.com/invoice-2.pdf", "format": "text" },
{
"url": "https://example.com/invoice-3.pdf",
"type": "attachment",
"returnMethod": "file",
"webhook": { "url": "https://example.com/hooks/invoice-3" }
}
],
"defaults": {
"format": "json",
"returnMethod": "inline",
"webhook": { "url": "https://example.com/hooks/batch-default" }
}
}{
"batchId": "batch_a1b2c3d4e5f6...",
"requests": [
{ "requestId": "req_...", "url": "https://example.com/invoice-1.pdf", "status": "queued" },
{ "requestId": "req_...", "url": "https://example.com/invoice-2.pdf", "status": "queued" },
{ "requestId": "req_...", "url": "https://example.com/invoice-3.pdf", "status": "queued" }
],
"pollUrl": "/v1/batch/batch_a1b2c3d4e5f6..."
}Poll Request Status
/v1/status/:requestIdPoll the status of an asynchronous conversion request. Returns the current status and, when complete, a presigned result URL or inline content depending on query parameters.
Query parameters
| Parameter | Type | Description |
|---|---|---|
returnMethod | string | When complete, return embedded content and contentType (same semantics as convert). Use inline. Default behaviour matches file. |
Response
Status values: pending, processing, complete, failed.
{
"requestId": "req_01J9X7K2M...",
"status": "complete",
"format": "json",
"type": "inline",
"detectedType": "inline",
"pagesProcessed": 3,
"creditsUsed": 1,
"resultUrl": "https://pdfpipe-results.s3...",
"expiresAt": "2026-02-23T12:00:00.000Z",
"processingDurationMs": 4230,
"createdAt": "2026-02-22T11:00:00.000Z",
"updatedAt": "2026-02-22T11:00:04.230Z"
}{
"requestId": "req_01J9X7K2M...",
"status": "complete",
"format": "json",
"type": "inline",
"pagesProcessed": 3,
"creditsUsed": 1,
"returnMethod": "inline",
"contentType": "application/json",
"content": { "pages": [ { "page": 1, "text": "..." } ] },
"returnMethodFallback": false,
"processingDurationMs": 4230,
"createdAt": "2026-02-22T11:00:00.000Z",
"updatedAt": "2026-02-22T11:00:04.230Z"
}Batch Status
/v1/batch/:batchIdCheck the overall status of a batch job and get individual request results.
{
"batchId": "batch_a1b2c3d4e5f6...",
"total": 3,
"completed": 2,
"failed": 0,
"pending": 1,
"requests": [
{ "requestId": "req_...", "status": "complete", "resultUrl": "https://..." },
{ "requestId": "req_...", "status": "complete", "resultUrl": "https://..." },
{ "requestId": "req_...", "status": "processing" }
]
}Usage
/v1/usageReturns your current month's usage statistics.
{
"month": "2026-02",
"requestCount": 47,
"tier": "starter"
}API Keys
/v1/keysList all API keys for your account.
{
"keys": [
{
"keyId": "a1b2c3d4e5f6",
"name": "Production key",
"prefix": "pk_live_",
"allowedIps": ["203.0.113.10"],
"createdAt": "2026-01-15T10:00:00.000Z",
"revokedAt": null
}
]
}/v1/keysCreate a new API key. The full key value is returned only in this response.
{
"name": "Production key",
"allowedIps": ["203.0.113.10"]
}{
"keyId": "a1b2c3d4e5f6",
"name": "Production key",
"prefix": "pk_live_",
"key": "pk_live_abc123...full_key_here"
}/v1/keys/:keyIdUpdate the IP allowlist on an existing API key. Pass an array of IP addresses to restrict the key, or an empty array / omit the field to allow all IPs. Cannot be used on revoked keys.
{
"allowedIps": ["203.0.113.10", "198.51.100.0"]
}{
"keyId": "a1b2c3d4e5f6",
"name": "Production key",
"prefix": "pk_live_",
"allowedIps": ["203.0.113.10", "198.51.100.0"],
"createdAt": "2026-01-15T10:00:00.000Z"
}/v1/keys/:keyIdRevoke an API key. Returns 204 No Content on success.
Error Codes
Errors return a JSON body with a code and human-readable message:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "url: URL must use http or https protocol"
}
}| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | Invalid or missing API key. |
VALIDATION_ERROR | 400 | Request body failed validation. Check the message for specifics. |
NOT_FOUND | 404 | The requested resource does not exist. |
FORBIDDEN | 403 | Insufficient permissions for this action. |
ACCOUNT_SUSPENDED | 403 | Account is suspended. Contact support. |
FILE_TOO_LARGE | 413 | PDF exceeds your tier's file size limit. |
RATE_LIMIT_EXCEEDED | 429 | Monthly request limit exceeded. |
SSRF_BLOCKED | 403 | URL points to a blocked private address. |
ATTACHMENT_LIMIT_REACHED | 403 | Monthly attachment request limit reached (Free/Starter only). |
FORMAT_NOT_ALLOWED | 403 | Output format not available on your tier. |
PROCESSING_ERROR | 500 | Internal processing failure. Retry or contact support. |
API_KEY_LIMIT_REACHED | 409 | Maximum number of API keys reached for this user. |
MEMBER_LIMIT_REACHED | 409 | Account team member limit reached. |
CHAT_NOT_AVAILABLE | 403 | Dashboard AI Help is available on Starter, Pro, and Business only. |
CHAT_RATE_LIMIT_EXCEEDED | 429 | Dashboard AI Help daily limit reached (50 questions per user per day). |
Rate Limits
Rate limits are applied per account on a monthly billing cycle. When you exceed your limit, requests return a 429 status. Business tier accounts can configure overage billing instead.
Dashboard AI Help is separate from PDF conversion quotas: paid plans (Starter+) include an in-dashboard assistant (Claude) at /dashboard/chat with documentation-grounded answers. Free tier does not include AI Help. Limit: 50 questions per user per calendar day (UTC). See also Getting Started.
| Tier | Requests/mo | Max File | Formats | Batch Size | API Keys | URL Expiry | AI Help |
|---|---|---|---|---|---|---|---|
| Free | 10 | 2 MB | json, text | 5 | 2 | 1 hour | No |
| Starter | 250 | 10 MB | All 10 | 25 | 5 | 24 hours | Yes (50/day) |
| Pro | 1,000 | 25 MB | All 10 | 50 | 10 | 7 days | Yes (50/day) |
| Business | 5,000 | 50 MB | All 10 | 100 | 25 | 30 days | Yes (50/day) |