Sail

Upload Receipt

POST/users/{user_id}/expenses/{expense_id}/receipt

Attach an itemized receipt to an expense to resolve an itemization_required classification (a mixed-basket transaction). Triggers asynchronous re-adjudication. The outcome arrives as a receipt.processed webhook (receipt.failed if unreadable). Alternative to an upload_receipt hosted session for customers who own the receipt UI themselves.

Path Parameters

user_idstringrequired

The Sail user id.

expense_idstringrequired

The Sail expense id.

Body multipart/form-data

filestring<binary>required

Receipt image or PDF.

Response

Receipt accepted. Re-adjudication queued.

statusstring

The job’s current status.

job_idstring

Identifier for tracking this asynchronous job.

Standard error envelope covering 400, 401, 403, 404, 429, and 500.

errorobject

The error detail.

Show error properties
codestring

Machine-readable code, e.g. not_found, token_scope_mismatch, product_not_enabled, insufficient_key_scope, insufficient_token_scope, user_token_required, user_token_expired, invalid_user_token, invalid_key_configuration, connection_not_reconnectable, rate_limited.

messagestring

Human-readable error message. May change, so match on error.code instead.

paramstring

The request field that caused the error, when applicable. Null otherwise.

Request
curl -X POST "https://live.savewithsail.com/api/v1/users/<user_id>/expenses/<expense_id>/receipt" \
  -H "Content-Type: multipart/form-data" \
  -H "Authorization: Bearer <token>" \
  -d '{
  "file": "string"
}'
Response
{
  "status": "processing",
  "job_id": "string"
}