API Reference

Upload PDFs and run AI extraction against your templates programmatically. Every response is JSON.

Authentication

Generate a key from Settings → API Keys. Send it as a bearer token on every request:

Authorization: Bearer pd_...

Keys are shown once at creation and only their hash is stored afterward — if you lose one, revoke it and create a new one. There is no separate test/live mode; a key works against your account's real templates, documents, and credit balance.

Rate limits

60 requests per rolling 60-second window, per key. Requests beyond that return 429 with a message telling you the limit.

Errors

Errors are a JSON object with an error string and one of these status codes:

400  Bad request (missing/invalid field)
401  Missing, invalid, or revoked API key
402  Not enough page-credits for this document -- upgrade your plan
404  Document or template not found (or not yours)
429  Rate limit exceeded
500  Something failed on our end

Quickstart

Upload a PDF or image (JPEG, PNG, GIF, WebP — Claude reads images natively, no separate OCR step) and run extraction against a template in one call:

curl https://<your-domain>/api/v1/documents \
  -H "Authorization: Bearer pd_..." \
  -F "file=@invoice.pdf" \
  -F "template_id=<template_id>"

Omit template_id to just upload the file, then trigger extraction later with a separate call to POST /api/v1/documents/{id}/extract.

Endpoints

GET/api/v1/templates

List your templates, so you know which template_id to pass when uploading or extracting.

curl https://<your-domain>/api/v1/templates \
  -H "Authorization: Bearer pd_..."

{
  "templates": [
    { "id": "...", "name": "Invoice", "description": null, "fields": [...], "created_at": "..." }
  ]
}
POST/api/v1/documents

Upload a file as multipart/form-data. Accepts application/pdf (max 20MB) or an image — image/jpeg, image/png, image/gif, or image/webp (max 10MB). Pass template_id to also run extraction in the same request.

curl https://<your-domain>/api/v1/documents \
  -H "Authorization: Bearer pd_..." \
  -F "file=@invoice.pdf" \
  -F "template_id=<template_id>"

# 201 Created
{
  "document": { "id": "...", "filename": "invoice.pdf", "status": "completed", ... },
  "extraction": { "id": "...", "status": "success", "extracted_data": { ... }, ... }
}

If extraction fails after a successful upload, you still get 201 with an extraction_error field alongside the uploaded document instead of an extraction field.

GET/api/v1/documents

List your documents, newest first. Supports limit (default 20, max 100) and offset query params.

curl "https://<your-domain>/api/v1/documents?limit=10" \
  -H "Authorization: Bearer pd_..."

{ "documents": [ { "id": "...", "filename": "...", "status": "completed", ... } ], "limit": 10, "offset": 0 }
GET/api/v1/documents/{id}

Document status plus its latest extraction result, if any.

curl https://<your-domain>/api/v1/documents/<document_id> \
  -H "Authorization: Bearer pd_..."

{
  "document": { "id": "...", "status": "completed", ... },
  "extraction": { "status": "success", "extracted_data": { ... }, ... }
}
POST/api/v1/documents/{id}/extract

Run (or re-run) extraction against an already-uploaded document.

curl -X POST https://<your-domain>/api/v1/documents/<document_id>/extract \
  -H "Authorization: Bearer pd_..." \
  -H "Content-Type: application/json" \
  -d '{"template_id": "<template_id>"}'

{ "extraction": { "status": "success", "extracted_data": { ... }, ... } }