Skip to main content
Automatically pulling supplier invoices into your system removes the need for manual data entry and gives your finance team real-time visibility into what is owed and when. In this guide, we will fetch all supplier invoices updated since the last sync, paginate through results, and download their attachments; using the same polling pattern as client invoices, with different endpoints and filters.
Example: A spend management tool syncs supplier invoices from Qonto nightly to match them against purchase orders and flag any discrepancies before payment.
Prerequisites:
  • At least one supplier invoice exists in Qonto.
  • Scopes: supplier_invoice.read, attachment.read
1

Initialize the sync timestamp

Same approach as client invoices: load the last successful sync timestamp from your database and capture the current time.
from datetime import datetime, timezone

BASE_URL = "https://thirdparty.qonto.com/v2"
headers = {"Authorization": "Bearer {your_access_token}"}

last_sync_at = "2026-01-01T00:00:00Z"  # Load from your database
current_sync_at = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
2

Fetch all supplier invoices updated in the time window

List supplier invoices updated between your last sync and now, sorted chronologically and paginated.Endpoint: List supplier invoices
OAuth scope required: supplier_invoice.read.
Additional filters are available: filter[status] (e.g., to_review, to_pay, paid), filter[due_date], and filter[created_at_from] / filter[created_at_to].
def fetch_all_supplier_invoices(last_sync_at, current_sync_at):
    invoices = []
    page = 1

    while True:
        response = requests.get(
            f"{BASE_URL}/supplier_invoices",
            headers=headers,
            params={
                "filter[updated_at_from]": last_sync_at,
                "filter[updated_at_to]": current_sync_at,
                "sort_by": "updated_at:asc",  # Process chronologically
                "per_page": 100,
                "page": page,
            },
        )
        response.raise_for_status()
        data = response.json()

        invoices.extend(data["supplier_invoices"])

        if data["meta"]["next_page"] is None:
            break
        page = data["meta"]["next_page"]

    return invoices

invoices = fetch_all_supplier_invoices(last_sync_at, current_sync_at)
print(f"Fetched {len(invoices)} supplier invoices")
3

Retrieve and download attachments

For each invoice with an attachment_id, fetch the attachment and download the file. The attachment URL expires in 30 minutes — download immediately.Endpoint: Retrieve an attachment
OAuth scope required: attachment.read.
import os

for invoice in invoices:
    if not invoice.get("attachment_id"):
        continue

    attachment_response = requests.get(
        f"{BASE_URL}/attachments/{invoice['attachment_id']}",
        headers=headers,
    )
    attachment_response.raise_for_status()
    attachment = attachment_response.json()["attachment"]

    file_response = requests.get(attachment["url"])
    file_response.raise_for_status()

    os.makedirs("./supplier_invoices", exist_ok=True)
    with open(f"./supplier_invoices/{attachment['file_name']}", "wb") as f:
        f.write(file_response.content)

    print(f"Downloaded: {attachment['file_name']}")
4

Store the sync timestamp

Persist the new sync timestamp only after full success.
save_to_db("last_supplier_invoice_sync_at", current_sync_at) # Use your own tools here
print(f"Sync complete. Next run will start from: {current_sync_at}")
Example output:
[Step 1] Initialize sync timestamps
  lastSyncAt:    2026-03-18T00:00:00Z
  currentSyncAt: 2026-03-19T16:50:12.227Z

[Step 2] GET /supplier_invoices (paginated)
  Fetched 2 supplier invoices

[Step 3] Download attachments
  Downloaded: supplier_invoice_1.pdf
  Downloaded: supplier_invoice_2.pdf

[Step 4] Store sync timestamp
  Sync complete. Next run will start from: 2026-03-19T16:50:12.22
We now have an up-to-date local copy of all supplier invoices and their attachments for the given time window.