Skip to main content
Attachment handling ensures that supporting documents (receipts, invoices) are transferred and linked to accounting entries in your Accounting System.

Prerequisites

Before you begin:

Relevant Export Item Fields

  {
      "companyId": "12abc3d4-e567-890e-1234-abc56e78fabc",
      "accountingEntryId": "59540ed2-0d68-4e36-9e31-58223975d9e9",
      "type": "card_purchase",
      "subType": null,
      "date": "2025-12-10T15:46:34Z",
      "amount": {
        "inSupplierCurrency": {
          "currency": "GBP",
          "value": 6366
        },
        "inWalletCurrency": {
          "currency": "GBP",
          "value": 6366
        }
      },
      "note": "Printer ink",
      "files": [
        {
          "url": "<string>",
          "type": "image/jpeg",
          "size": 13010
        }
      ],
      "supplier": {
        "code": "1340472473",
        "name": "Target",
        "categoryCode": "1000",
        "country": "GB",
        "account": null,
        "taxIdentifier": null
      },
      "user": {
        "id": "6b71f6bd-e83d-4d49-88ee-2b8cda2d57cf",
        "name": "Luke Richardson",
        "code": null
      },
      "team": {
        "id": "747aaf60-56c6-4b46-ad92-f8a0cb59cf8b",
        "code": "5678",
        "name": "Engineering"
      },
      "accountingEntryLines": [
        {
          "accountingEntryLineId": "0c76ea71-aaaa-4ece-bb68-e1166ccaea04",
          "lineAmount": {
            "inSupplierCurrency": {
              "currency": "GBP",
              "value": 6366
            },
            "inWalletCurrency": {
              "currency": "GBP",
              "value": 6366
            }
          },
          "netAmount": {
            "inSupplierCurrency": {
              "currency": "GBP",
              "value": 6366
            },
            "inWalletCurrency": {
              "currency": "GBP",
              "value": 6366
            }
          },
          "account": {
            "id": "7966c3ba-e4de-4574-8604-6cfa48d62cc8",
            "code": "6990000",
            "name": "Printing & Stationary",
            "identifier": "6990000"
          },
          "tax": {
            "id": "997d8526-5872-484d-ba07-c7a07e08e555",
            "code": "0001",
            "type": "inclusive",
            "amount": {
              "inSupplierCurrency": {
                "currency": "GBP",
                "value": 0
              },
              "inWalletCurrency": {
                "currency": "GBP",
                "value": 0
              }
            },
            "rate": 0.00
          },
          "tags": []
        }
      ],
      "additionalInformation": {
        "reconciliationId": "2500001",
        "reconciledEntries": null,
        "attendees": [],
        "invoiceInformation": null
      },
      "bookkeeping": {
        "method": "journal"
      },
      "vendor": {
        "id": "22e1f2c9-1360-4291-ab41-6b23dcea8888",
        "name": "TestVendor",
        "code": "acc1234",
        "externalId": "ext12345",
        "registrationNumber": "reg001234",
        "taxRegistrationNumber": "taxreg1234",
        "country": "UK",
        "defaultCurrency": "GBP"
      },
      "contraAccount": {
        "id": "993d664c-9b7c-4efc-a677-510e69200857",
        "code": "0876000",
        "name": "0876000_ChartAccounts",
        "identifier": "0876000"
      },
      "_links": {
        "web": {
          "exportItem": "https://app.staging.pleo.io/export/export-item/0c76ea71-aaaa-4ece-bb68-e1166ccaea04"
        }
      },
      "servicePeriod": null
    },
   # [other Export Items omitted for brevity]
   # [Pagination omitted for brevity]
Attachments are provided in:
"files": [
  {
    "url": "https://file.url",
    "type": "application/pdf",
    "size": 13010
  }
]
Each Export Item may contain:
  • zero attachments
  • one attachment
  • multiple attachments

Steps

1. Check for Attachments

if files is empty:
    continue processing

2. Download Attachments

Iterate through all files:
attachments = []

for file in files:
    attachment = download(file.url)
    attachments.append(attachment)
Guidelines:
  • download immediately (URLs may expire)
  • preserve file format and filename where possible

3. Handle Multiple Attachments

If multiple attachments exist:
if accountingSystem.supportsMultipleAttachments:
    upload all attachments
else:
    mergedFile = merge(attachments)
    upload mergedFile
Recommended merge strategies:
  • PDF merge (preferred)
  • ZIP archive (fallback)

4. Upload and Associate Attachments

Attach files to the created record:
  • journal entry
  • vendor invoice (AP)
  • expense transaction
for attachment in attachments:
    uploadToAccountingSystem(entryId, attachment)
Ensure:
  • attachments are linked to the correct entry
  • traceability to the original Export Item is preserved

5. Handle Failures

Attachment failures must be handled explicitly.
try:
    download/upload
except transientError:
    retry
except permanentError:
    log failure
Recommended behaviour:
  • retry transient failures (network/timeouts)
  • log all failures
  • decide whether to:
    • fail the Export Item, or
    • continue without attachment (system-dependent)

6. Ensure Idempotency

Avoid duplicate uploads when retrying exports.
if attachmentAlreadyUploaded(file):
    skip upload
Strategies:
  • Generate a deterministic attachment key, for example:
    • accountingEntryId + file index, or
    • a hash of file metadata (e.g. URL, size, type)
  • Store processed attachment keys to prevent duplicate uploads during retries
  • Optionally check existing attachments in the Accounting System (if supported)

Results

After completing this step:
  • All available attachments have been:
    • downloaded
    • uploaded
    • linked to accounting entries
  • Attachments remain traceable to their originating Export Item

What Comes Next?


this how-to is part of: