API Recipes: Upload, Convert, and Fetch Results
End-to-end code for the most common DocuClipper API workflows: upload a PDF, run a bank or invoice job, poll for completion, and fetch the structured results.
Last updated
This article gives you copy-paste recipes for the DocuClipper Agent API. It assumes you already have a Personal Access Token. If not, start with API Access (Personal Access Tokens).
All endpoints below live under https://www.docuclipper.com/api/v1/agent and require the Authorization: Bearer <PAT> header (PATs start with dcp_). The agent API supports three job types: ExtractData (bank and credit card statements, plus check images via subType: "checkImages"), Invoice (sales invoices, bills, receipts), and Form (tax forms such as W-2 and 1099). For anything else, use the web UI.
The four-step flow
Every conversion follows the same shape:
- Ask DocuClipper for a presigned upload URL.
- PUT your PDF to that URL.
- Create a job referencing the document.
- Poll the job until it succeeds, then fetch the data.
Recipe 1: Convert a bank statement to JSON
TOKEN="dcp_xxxxxxxx"
BASE="https://www.docuclipper.com/api/v1/agent"
PDF="/path/to/statement.pdf"
# 1. Get a presigned upload URL.
RESP=$(curl -sS -X POST "$BASE/documents/upload-url" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"filename\":\"$(basename "$PDF")\",\"mimetype\":\"application/pdf\"}")
DOC_ID=$(echo "$RESP" | jq -r .document.id)
UPLOAD_URL=$(echo "$RESP" | jq -r .url)
# 2. Upload the PDF directly to S3.
curl -sS -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary "@$PDF"
# 3. Create the job. ExtractData defaults to bank mode.
JOB=$(curl -sS -X POST "$BASE/jobs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"jobType\":\"ExtractData\",\"documents\":[$DOC_ID],\"jobName\":\"My statement\"}")
JOB_ID=$(echo "$JOB" | jq -r .jobId)
# 4. Poll for completion (status transitions: Created -> InProgress -> Succeeded / Failed).
while :; do
STATUS=$(curl -sS "$BASE/jobs/$JOB_ID" -H "Authorization: Bearer $TOKEN" | jq -r .status)
echo "status: $STATUS"
[ "$STATUS" = "Succeeded" ] && break
[ "$STATUS" = "Failed" ] && exit 1
sleep 5
done
# 5. Fetch the structured payload.
curl -sS "$BASE/jobs/$JOB_ID/data" -H "Authorization: Bearer $TOKEN" > result.json
The data endpoint returns transactions grouped by document and account, including the bank-mode reconciliation flags. If you only need a flat list of transactions, use the recipe below instead.
Recipe 2: Get just the transactions (CSV or JSON)
# Flat JSON list (header / OCR-noise rows filtered out by default).
curl -sS "$BASE/jobs/$JOB_ID/transactions" \
-H "Authorization: Bearer $TOKEN"
# CSV download.
curl -sS "$BASE/jobs/$JOB_ID/transactions?format=csv" \
-H "Authorization: Bearer $TOKEN" -o transactions.csv
# Include raw rows (headers, footers, OCR noise) for debugging.
curl -sS "$BASE/jobs/$JOB_ID/transactions?includeRaw=true" \
-H "Authorization: Bearer $TOKEN"
Default limit is 1000, max 10000. If you have a multi-thousand-row statement, paginate by re-running with a larger limit. There is no offset cursor today; the agent endpoint is optimized for one-call retrieval.
Prefer the per-document endpoints. Extracted rows are stored per document, so GET /documents/:documentId/transactions and GET /documents/:documentId/data are the direct read, and they work for every document on the account rather than only jobs this token created. The job-keyed endpoints above stay supported for existing integrations. Recipe 5 shows how to get document ids.
Recipe 3: Convert an invoice or receipt
# Same upload step as recipe 1 (steps 1-2). Then create with jobType=Invoice.
curl -sS -X POST "$BASE/jobs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"jobType\":\"Invoice\",\"documents\":[$DOC_ID]}"
After the job succeeds, GET /jobs/$JOB_ID/data returns the InvoiceExport shape: vendor, invoice number, dates, totals, line items.
Tax forms follow the same pattern with "jobType":"Form". The data endpoint returns the extracted form fields (for example the boxes on a W-2 or 1099).
Recipe 4: Convert several PDFs in one job
Pass an array of document IDs. DocuClipper processes them as a single batch:
curl -sS -X POST "$BASE/jobs" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"jobType\":\"ExtractData\",\"documents\":[$DOC1,$DOC2,$DOC3]}"
The job's data payload returns one block per document, keyed by document ID. Use this when you have a multi-statement archive from one client and want a single result file.
Recipe 5: Find documents that arrived from a connected folder
Recipes 1 to 4 all assume you created the job, so you have the job id. Documents that arrive another way have no job id you can guess: a Box, Dropbox, Google Drive, or OneDrive folder connected to a project, an ingestion email address, or a colleague uploading through the web UI. Reach those by project.
# 1. List the projects this token can read.
curl -sS "$BASE/projects" -H "Authorization: Bearer $TOKEN"
# 2. List the documents in one project, newest first.
PROJECT_ID=319091
curl -sS "$BASE/projects/$PROJECT_ID/documents?limit=50" \
-H "Authorization: Bearer $TOKEN"
# 3. Read the extracted rows for one of them.
DOC_ID=8461233
curl -sS "$BASE/documents/$DOC_ID/transactions" -H "Authorization: Bearer $TOKEN"
curl -sS "$BASE/documents/$DOC_ID/data" -H "Authorization: Bearer $TOKEN"
Each entry in step 2 carries everything you need to decide whether to fetch it:
| Field | Meaning |
|---|---|
status | pending, processing, completed, failed, canceled, or out_of_credits |
source | How it arrived: box_folder, dropbox_folder, gdrive_folder, onedrive_folder, digital, camera |
extractionType | ExtractData, Invoice, or Form |
transactionCount | Extracted rows available |
isReconciled | Bank statements only. true when every statement period balanced against the printed opening and closing balances; null when the document carries no balance information |
pages | Page count |
Page through a large project with limit (default 50, max 200) and offset. The response includes total so you know when to stop.
A polling loop over this endpoint is a reasonable way to watch a connected folder, but a webhook is better: see the last section of this article.
Recipe 6: Check who you are and your remaining quota
curl -sS "$BASE/whoami" -H "Authorization: Bearer $TOKEN"
Returns your contract ID, plan, scopes, and (if your plan uses agent billing) pagesUsed vs pagesFree. Hit this first to confirm the token is valid and you have headroom before queuing work.
Common mistakes
- Fetching
/databefore extraction finishes returns 409. Poll/jobs/:id(or/documents/:documentId, whosestatusreachescompleted) first. - Assuming a document has a job id you can reach.
GET /jobs/:idonly resolves jobs your own token created. For anything uploaded through a connected folder, an ingestion email, or the web UI, start fromGET /projects(recipe 5). - Setting
jobTypeto an unsupported value returns 400. The agent API acceptsExtractData,Invoice, andFormonly. Anything else (for exampleReceipt) is rejected — use the web UI for those document types. - Re-using the presigned upload URL. Each URL is single-use. If the PUT fails, request a new URL.
- Forgetting
Content-Type: application/pdfon the PUT. S3 stores the wrong MIME type and downstream OCR can break. - Token in URL or logs. Use the
Authorizationheader, never a query string. Avoidcurl -von requests with a bearer token (the verbose log prints the header).
Webhooks instead of polling
For production, replace the polling loop with a webhook subscription so DocuClipper pushes you a job.succeeded event. See Webhooks Overview for the subscription endpoint and event shape.