Skip to Content
HelvetlyDocs
API referenceExpenses

Upload receipts to an expense

Needs a token with the write:expenses scope. Authentication

Try in Playground sends a real request to app.helvetly.com with a token you paste. It stays in this browser tab only (session storage) and goes to no one else.

POST
/api/v1/expenses/{id}/receipts

Attaches 1 to 10 receipts (multipart field files[], each up to 20 MB; PDF, JPEG, PNG, WebP or HEIC/HEIF, checked by their bytes) to a draft or booked expense; a voided expense answers 409 invalid_state. Receipts added to a booked expense are retention-locked. All files are checked before any is stored: 422 validation_failed (fields.files) for a wrong type or size, 413 payload_too_large. Duplicate check: the SHA-256 of each file's actual bytes is compared inside the workspace with live Documents, client files and receipts on non-deleted expenses; identical bytes answer 409 duplicate_file whatever the name, with details {existing_id, existing_name, resource: document or receipt, expense_id?} (details are left out when the caller may not read that resource). The same bytes twice in one request answer 409 duplicate_file with details {existing_name, resource: upload}, before anything is stored, and nothing from the batch is kept. Trashed documents and deleted expenses do not block. Another workspace never matches. Retrying a request that succeeded answers 409 duplicate_file, so it is safe.

Authorization

bearerAuth
headerAuthorizationBearer <token>

A personal API token, hvt_…, with scopes such as read:* or write:invoices

Path Parameters

id*string

The expense's id.

Request Body

multipart/form-data
  1. body
files[]*array<>

1 to 10 receipts, each up to 20 MB: PDF, JPEG, PNG, WebP or HEIC/HEIF (decided by the file's bytes, not its name).

Itemsitems <= 10

Response Body

Created

application/json
  1. response
data*array<>
Example Request
curl -X POST 'https://app.helvetly.com/api/v1/expenses/string/receipts' \  -F 'files[]=[  "string"]'
Example Response
{  "data": [    {      "id": "string",      "name": "string",      "size": 0,      "content_type": "string",      "created_at": "2019-08-24T14:15:22Z",      "uploaded_by": {        "id": "string",        "name": "string"      }    }  ]}