Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dolfinai.co/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks through the end-to-end flow of processing a bill via the Dolfin API. You’ll upload a bill document, optionally correct any fields the OCR scanner got wrong, submit the bill for review, and either approve or reject it.

Prerequisites

  • A Dolfin API key
  • An organisation already provisioned (see Client Integration)
  • A valid session token or API key for authentication
  • A bill PDF or image file to upload
All requests below require the x-dolfin-api-key and x-dolfin-organisation-id headers. See Authentication for details.

Overview

1

Upload a bill

Upload the bill document. Dolfin queues OCR processing asynchronously.
2

Patch extracted fields (optional)

Fix any fields the OCR scanner got wrong while the bill is in PendingReview.
3

Submit for review

Move the bill from PendingReview into NeedsApproval.
4

Approve or reject

Approve the bill to proceed to payment scheduling, or reject it with a reason.

Bill lifecycle

A bill moves through these states:
Created → OcrProcessing → PendingReview → NeedsApproval → Approved → Scheduled → Paid
                     ↘ OcrFailed                        ↘ Rejected

Step 1: Upload a Bill

Upload the bill document as multipart/form-data. OCR runs asynchronously, so the response returns immediately with the new bill’s id and initial state.
curl -X POST https://api.dolfinai.co/bills \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8" \
  -F "file=@./acme-invoice-2025-01.pdf"
Response (202 Accepted):
{
  "id": "b1234567-abcd-ef01-2345-6789abcdef01",
  "state": "OcrProcessing"
}
Save the bill id — you’ll use it in every subsequent call. The bill starts in OcrProcessing and automatically moves to PendingReview once the scanner finishes. Poll GET /bills/{id} to check, or subscribe to the /hubs/bills SignalR hub for realtime updates.

Poll for OCR completion

curl https://api.dolfinai.co/bills/b1234567-abcd-ef01-2345-6789abcdef01 \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8"
Once the state is PendingReview, the OCR results are populated on the bill:
{
  "id": "b1234567-abcd-ef01-2345-6789abcdef01",
  "state": "PendingReview",
  "supplierName": "Acme Supplies Ltd",
  "supplierEmail": "billing@acme.co.uk",
  "invoiceNumber": "ACM-2025-0142",
  "invoiceDate": "2025-01-15T00:00:00Z",
  "dueDate": "2025-02-14T00:00:00Z",
  "currency": "GBP",
  "subTotal": "480.00",
  "taxAmount": "96.00",
  "totalAmount": "576.00",
  "ocrConfidence": 0.94,
  "lineItems": [
    {
      "id": "li-0001",
      "description": "Bulk stationery order",
      "quantity": "10",
      "unitPrice": "48.00",
      "taxRate": "20",
      "taxAmount": "96.00",
      "subTotal": "480.00"
    }
  ]
}
If the state becomes OcrFailed, the document couldn’t be parsed. Call POST /bills/{id}/retry-ocr to try again.

Step 2: Patch Extracted Fields (Optional)

OCR isn’t perfect. If the scanner got any fields wrong — the supplier name, invoice number, amounts, line items, bank details — patch them while the bill is in PendingReview.
curl -X PATCH https://api.dolfinai.co/bills/b1234567-abcd-ef01-2345-6789abcdef01 \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8" \
  -H "Content-Type: application/json" \
  -d '{
    "invoiceNumber": "ACM-2025-00142",
    "totalAmount": "576.00",
    "accountHolderName": "Acme Supplies Ltd",
    "accountNumber": "12345678",
    "sortCode": "20-00-00",
    "bankCountry": "GB",
    "bankCurrency": "GBP"
  }'
Only the fields you include are updated — everything else stays as OCR extracted it. You can only patch bills in PendingReview; attempts against any other state return 409 Conflict.
To link the bill to an existing supplier record, set supplierId to the supplier’s UUID. Otherwise the free-text supplierName, supplierEmail, etc. are kept as-is and used for supplier resolution when you submit for review (see Step 3).

Step 3: Submit for Review

Once the extracted data is correct, submit the bill for approval. This transitions the state from PendingReview to NeedsApproval.

Supplier resolution

When you submit a bill for review, Dolfin resolves the bill’s supplier in this order:
  1. If you set supplierId explicitly (via patch), that supplier is used.
  2. Otherwise, Dolfin looks for an existing supplier on the organisation whose tax ID or email matches the OCR-extracted value and links to it.
  3. If no match is found, a new supplier is created from the OCR data. This requires at minimum supplierName and supplierEmail — fill these via PATCH /bills/{id} in Step 2 if OCR didn’t capture them. Any other extracted details (phone, address, website, tax ID, bank details) are copied onto the new supplier too.
If the bill has no linked supplier and not enough data to create one, submit-review returns 400 Bad Request.
curl -X POST https://api.dolfinai.co/bills/b1234567-abcd-ef01-2345-6789abcdef01/submit-review \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8"
Response:
{
  "id": "b1234567-abcd-ef01-2345-6789abcdef01",
  "state": "NeedsApproval",
  "invoiceNumber": "ACM-2025-00142",
  "totalAmount": "576.00",
  "currency": "GBP"
}

Step 4: Approve or Reject

With the bill in NeedsApproval, an approver takes the final call.

Approve

curl -X POST https://api.dolfinai.co/bills/b1234567-abcd-ef01-2345-6789abcdef01/approve \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8"
Response:
{
  "id": "b1234567-abcd-ef01-2345-6789abcdef01",
  "state": "Approved",
  "approvedBy": "u5678901-abcd-ef01-2345-6789abcdef01",
  "approvedAt": "2025-01-20T09:10:00Z"
}
An approved bill is ready for payment scheduling via POST /bills/{id}/schedule-payment.

Reject

If something’s off, reject the bill with an optional reason.
curl -X POST https://api.dolfinai.co/bills/b1234567-abcd-ef01-2345-6789abcdef01/reject \
  -H "x-dolfin-api-key: dol_live_abc123" \
  -H "x-dolfin-organisation-id: 9a658587-fe02-402e-b1ac-bfaf53274ef8" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Duplicate of ACM-2025-00141"
  }'
Response:
{
  "id": "b1234567-abcd-ef01-2345-6789abcdef01",
  "state": "Rejected",
  "rejectedBy": "u5678901-abcd-ef01-2345-6789abcdef01",
  "rejectedAt": "2025-01-20T09:10:00Z",
  "rejectionReason": "Duplicate of ACM-2025-00141"
}
A rejected bill can be re-opened for editing with POST /bills/{id}/reopen, which returns it to PendingReview.

Summary

StepEndpointWhat it does
1POST /billsUpload a bill document; OCR runs asynchronously
2PATCH /bills/{id}Correct any fields OCR got wrong (optional)
3POST /bills/{id}/submit-reviewTransition from PendingReview to NeedsApproval
4aPOST /bills/{id}/approveApprove the bill for payment
4bPOST /bills/{id}/rejectReject with an optional reason

Next Steps

API Reference

Explore the full Bills API, including payment scheduling and file URLs.

Client Integration

Set up organisation provisioning and user authentication.