Documentation Index
Fetch the complete documentation index at: https://docs.tesouro.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Once transactions are in the system, the goal is to make it as easy as possible for employees to collect receipts, fill in descriptions, and get their expenses approved. Receipt collection is the first step—employees can upload receipts directly, forward them by email, or have them auto-matched to a transaction. As soon as a receipt is matched to a transaction, Tesouro auto-fills the accounting fields, so by the time the employee opens the expense it’s largely ready to submit. From there the expense moves through the approval flow and is categorized and ready for accounting export.Receipt collection
The first step is for the employee to upload receipts, either:- Direct link: Upload the receipt and immediately link it to a specific transaction by sending
PATCH /receipts/{receipt_id}with thetransaction_id. Use this when the employee has the receipt in hand and knows which transaction it belongs to. - Auto-matching: Upload the receipt (via file upload, or email forwarding) without specifying a transaction. The auto-matching engine finds the right transaction based on amount, merchant name, and timestamp. See Receipts & OCR for upload paths and matching details.
ledger_account_id: Tesouro compares the receipt content against the organization’s ledger accounts and selects the best match. Setssource_of_data.ledger_account_idto"generated".description: If the transaction has no description, the AI generates a concise memo (e.g."Dinner in NYC"or"Taxi ride"). Setssource_of_data.descriptionto"generated". If it can’t produce a confident summary, the field is left empty.
Auto-categorization requires at least one ledger account to be configured. See Configure accounting fields.
Submit for approval
CallPOST /transactions/{id}/submit to move the transaction from new to approve_in_progress. Tesouro enforces all configured requirements before the status changes — if any required fields are missing, the call returns a list of errors and the transaction stays in new:
receipt_id is required and missing:
expense_status: "approve_in_progress":
applied_policy_id and notifies the designated approvers.
Submit without a receipt
If an employee can’t provide a receipt, they can bypass receipt validation by settingbypass_receipt_validation: true and supplying a no_receipt_reason. This records the exception for audit purposes:
no_receipt_reason is stored on the transaction and visible to approvers. The has_validation_errors field on the response will be true to flag that the submission bypassed a requirement.
See POST /transactions/{id}/submit for the full API reference.
Approval
Policy-driven approval
When a transaction is submitted, Tesouro runs it against the active approval policies. If a policy matches:applied_policy_idis set on the transaction to identify which policy is running.- The policy’s script determines who must approve. This could be a specific user list, any user with a given role, or the employee’s reporting manager.
approve_in_progress until it is force-approved or rejected by an admin.
List pending approval requests
The designated approver can fetch their outstanding requests:The
roles field and role-based approval_type values are being refactored. Treat role-related fields as subject to change.Approve the request
expense_status: "approved". Use GET /transactions/{id} to confirm the final state.
Force approve
POST /transactions/{id}/approve bypasses the normal policy-driven flow. Use it in two situations:
- No policy matched: The transaction is in
approve_in_progressbut no policy applied. Call this to approve it directly. - Admin override: A policy is running but an admin needs to approve immediately, regardless of the policy’s designated approvers.
expense_status: "approved".
Reject a transaction
A transaction can be rejected in two ways, mirroring the two approval paths:- Via the approval request: The designated approver rejects the pending approval request. Use this in the normal policy-driven flow.
- Force reject: An admin rejects the transaction directly, bypassing or overriding the policy. Use this when no policy applied or an admin needs to override.
Reject via approval request
Force reject
reject_reason is stored on the transaction and visible to the employee. A rejected transaction is still accessible in the system, but the employee must reopen it (POST /transactions/{id}/reopen) before it can be submitted again.
See POST /transactions/{id}/reject and POST /approval-requests/{id}/reject for the full API reference.
Accounting field auto-population
Transactions carry asource_of_data JSON object that records how each field was set. Fields like ledger_account_id, description, receipt_id, location_id, and department_id are all auto-populated but overridable — employees and admins can update any of them, and the entry in source_of_data updates to "user" to reflect that.
source_of_data on transactions
Each entry in thesource_of_data object takes one of these values:
| Value | Meaning |
|---|---|
"user" | The employee or admin explicitly set this value. |
"generated" | Auto-generated by Tesouro when a receipt was matched (e.g., ledger_account_id and description). |
"automatched" | Set automatically by Tesouro — either by the AI receipt matching engine (receipt_id) or from the employee’s profile (location_id, department_id). |
null | This field hasn’t been set yet. |
location_id and department_id are auto-assigned from the employee’s user profile when the transaction is created. When an employee edits only one field, the other fields’ source_of_data entries are preserved — only the changed field’s origin updates to "user".
source_of_data on receipts
Receipts have their ownsource_of_data field that records how the receipt’s data was captured — separate from the transaction tracking above:
| Value | Meaning |
|---|---|
"ocr" | The receipt was created from a file upload. Tesouro’s OCR service extracted the structured fields. |
"user_specified" | The receipt was created by sending structured data directly to POST /receipts — no file, no OCR. |
source_of_data.receipt_id to "automatched" on the transaction. A manual match sets it to "user". This distinction is shown in the expense management UI so employees can see at a glance whether a receipt was attached automatically or still needs their attention.