Skip to main content

Understanding attachments in accounting systems

Most accounting systems let users attach supporting documents (PDFs, scanned images, receipts) to their bookkeeping records — typically on invoices (sales / purchase entries) and on journal entries (G/L entries). How those files are exposed varies a lot between connectors:
  • Some providers return a direct download URL for each attachment.
  • Others only signal that a document exists and require an additional API call to fetch the file content (returned as a base64-encoded string).
  • A few connectors don’t expose attachment information at all.
With the Unified API, you don’t need to know which behaviour applies to which connector — Chift normalises everything behind a single attachments_info object and a single retrieval endpoint.

How Chift handles attachments

Every invoice and every journal entry returned by the Accounting API includes an attachments_info object that tells you what to expect:

Status values

The recommended pattern is always the same: inspect attachments_info.status first, then either download the URL directly or call the dedicated attachments endpoint.

Retrieving invoice attachments

Invoices returned by the following endpoints include the attachments_info object:

1. When status is yes

The attachments array contains one or more entries with a direct URL. You can download the file straight from that URL — no additional API call needed.

2. When status is yes_to_request

The attachments array may be empty — the status only signals that a file is available. To get the actual content, call the Get attachments endpoint with type=invoice:
The response returns a list of objects with the file as a base64-encoded string:
You can then decode base64_string on your end to reconstruct the original PDF or image file.
Connectors such as Odoo typically fall into the yes_to_request category for invoices.

Retrieving journal entry attachments

Journal entries follow the exact same pattern as invoices. The attachments_info object is available on: The only difference is the type query parameter you pass when status is yes_to_request. Use type=entry:
The response shape is identical to the invoice case — a list of objects with an id and a base64_string.

End-to-end flow

A typical retrieval flow looks like this, regardless of whether you’re dealing with an invoice or a journal entry:
  1. Fetch the document (invoice or journal entry) from the corresponding GET endpoint.
  2. Read attachments_info.status.
  3. Branch on the status:
    • yes → download each file from the url in attachments.
    • yes_to_request → call GET /consumers/{consumer_id}/accounting/attachments with the right type (invoice or entry) and the document_id of the record, then decode base64_string.
    • no → no file to retrieve.
    • unknown → the connector does not expose attachment metadata; skip or surface this to the end user.