Skip to main content

Overview

A receipt is a digital file — PDF, PNG, JPEG, or GIF — representing proof of a purchase. Receipts can be created from structured data, uploaded from a file, or forwarded by email. Regardless of how a file arrives, Tesouro runs OCR to extract structured fields, and the AI auto-matching engine then tries to link the receipt to an existing transaction. Receipts created from structured data skip OCR entirely.

Upload paths

Direct upload (API or web)

Call POST /receipts/upload-from-file with the file as multipart/form-data. Tesouro accepts PDF, PNG, JPEG, and GIF files up to 20 MB:
The response is immediate. The receipt is created with source_of_data: "ocr" and OCR processing begins asynchronously:
The ocr_status field on the receipt tracks where processing is: When OCR finishes, fields like merchant_name, total_amount, issued_at, and currency are populated and you receive a receipt.ocr_finished webhook:

Email forwarding

Each organization has a dedicated mailbox. Employees forward receipt emails as attachments (PDF, PNG, JPEG, or GIF, up to 20 MB) to that address. Tesouro creates a receipt for each attachment and runs OCR automatically. To get an organization’s mailbox address, call GET /mailboxes:
Email-forwarded receipts show origin: "email" and the sender field contains the forwarding address. The receipt’s source_of_data is "ocr"—OCR still processes the attachment regardless of how it was delivered.
Mailboxes must be created with related_object_type: "receipt" to receive expense receipts. Mailboxes with type "payable" route to accounts payable, not expense management. See Mailboxes to set up a custom email domain.

Create a receipt from structured data

If you already have the receipt data in structured form (from a partner system or POS integration), use POST /receipts to create a receipt without a file. This skips OCR entirely:
You can also attach a file to an existing receipt at any time using POST /receipts/{id}/attach-file. See POST /receipts and POST /receipts/upload-from-file for the full API reference.

Auto-matching to transactions

After OCR completes, Tesouro’s AI auto-matching engine tries to link the receipt to an unmatched transaction in the same organization. It scores candidates based on amount, currency, merchant name, and timestamp proximity. The receipt is linked to the highest-scoring transaction that clears the match threshold and hasn’t already been matched. If no candidate clears the threshold, the receipt remains unmatched in the Receipts inbox. When the AI links a receipt, the transaction’s source_of_data.receipt_id is set to "automatched". At that point, the auto-categorization step fires and populates ledger_account_id and description on the transaction.
Each receipt can only be linked to one transaction. If a receipt is already matched, the auto-matching engine won’t re-link it.

Receipt bank and manual matching

Unmatched receipts accumulate in the Receipts inbox — retrievable via GET /receipts?has_transaction=false. Use the has_receipt=false filter on GET /transactions to find the other side: transactions still waiting for a receipt.

List unmatched receipts

Manual match

When auto-matching doesn’t find a match, or links the wrong transaction, manually link a receipt to a transaction by sending PATCH /receipts/{receipt_id} with the transaction_id:
A manual match sets source_of_data.receipt_id to "user" on the transaction, and link_source: "user" on the receipt. This distinguishes it from an AI-generated match in audit logs and in the UI. To remove a receipt from a transaction, send PATCH /receipts/{receipt_id} with "transaction_id": null. The receipt returns to the Receipts inbox. See GET /receipts and PATCH /receipts/{id} for the full API reference.