---
title: "List invoices"
method: GET
path: "/v1/invoices"
tags: ["Invoices"]
---

# List invoices

`GET /v1/invoices`

## Request

- Base URL: `https://api.getfinero.com/functions/v1/api`
- URL: `https://api.getfinero.com/functions/v1/api/v1/invoices`
- Auth: HTTP bearer

Lists the tenant's synced invoices, newest first by creation time. Cursor-paginated: pass `limit` (1–100) and send pagination.next_cursor back as `cursor` until has_more is false. To learn HOW MANY rows match without walking every page, pass `include_total=true` once and read pagination.total_count. Filters are allowlisted; combine freely. collection_status filters like any other field — it is a stored, indexed value, so it pages and counts exactly as the rest do and combines with ?include_total=true.

Available to **admin and readonly** API keys (no side effects).

## Query parameters

- `limit` integer
- `cursor` string
- `order` 'asc' | 'desc'
- `include_total` boolean
- `collection_status` 'paid' | 'open' | 'inactive'
- `currency` string
- `invoice_number` string
- `connection_id` string, uuid
- `updated_since` string, date-time
- `customer_id` string, uuid
- `erp_push_state` 'held' | 'pending' | 'processing' | 'posted' | 'failed'
- `has_active_payment_link` boolean
- `due_before` string, date
- `due_after` string, date

## Response `200`

Success

- object
  - `data` object[], required: Invoices, newest first by creation time.
    - `collection_mode` 'invoice' | 'installment', required: Collect from the invoice header or its real installment schedule.
    - `block_reasons` string[]: INVOICE MODE ONLY (`collection_mode: invoice`), where the invoice itself is what Finero collects and there are no installments to carry this: WHY it is not collectible, as stable codes — empty when nothing blocks it. The same codes, and the same derivation, as an installment's `block_reasons`; in installment mode read them there instead. Meanings: https://app.getfinero.com/guide.
    - `id` string, uuid, required: Invoice id (stable Finero identifier).
    - `invoice_number` string, nullable, required: Human-readable local or ERP invoice number.
    - `currency` string, nullable, required: Invoice currency. ISO 4217 alphabetic code, e.g. "USD".
    - `total_amount` string, nullable, required: Invoice total. Null while the ERP has none yet (a draft). Exact decimal string at the CURRENCY'S own scale — USD "1250.00", JPY "1250", BHD "1250.000". Never parse as float for arithmetic.
    - `invoice_date` string, date, nullable, required: Invoice date (YYYY-MM-DD).
    - `due_date` string, date, nullable, required: Invoice due date (YYYY-MM-DD).
    - `payment_terms` string, nullable, required: The invoice's payment terms exactly as your ERP names them (for example `NET30`). Informational: due dates come from `due_date` and `collection_due_date`, never from the terms. Null when the ERP sent none, when the connection does not collect them, and for local invoices.
    - `collection_due_date` string, date, nullable, required: Due date for collectible invoice worklists: the invoice header date in invoice mode, or the earliest collectible installment date in installment mode. Null if nothing is collectible or no due date is available. Use Aging operations for the full dated balance report. Filter with due_before / due_after.
    - `last_synced_at` string, date-time, nullable, required: When Finero last read this invoice FROM the ERP. Use it to ask whether a row is still current with your ERP — `updated_at` cannot answer that, because Finero's own writes to the invoice move it too (marking an invoice no longer present; recording a payment on an invoice created in Finero), so a row can look freshly updated while the ERP has not been heard from in weeks. Finero's collection state alone does not move `updated_at`. Null for invoices created in Finero, which have no ERP to read from, and for a few rows that predate the field. (ISO 8601 UTC).
    - `collection_outstanding` string, nullable, required: What Finero still has to collect on this invoice, as an exact decimal string. Null while the ERP has no amount yet (a draft): unknown, never zero. THIS IS THE FIELD THAT ACCOUNTS FOR PAYMENTS FINERO HAS ALREADY TAKEN, including before your ERP has been told about them; payments and changes made in your ERP arrive with the next sync. Zero for an invoice no longer present in your ERP. Sum this for what is owed: the summary's totals are this sum.
    - `amount_collected` string, required: How much Finero has confirmed collected on this invoice, as an exact decimal string. Money taken through a Finero payment link only - a payment made directly to you, or settled in your ERP, is not counted here and leaves this at zero.
    - `erp_push_state` 'held' | 'pending' | 'processing' | 'posted' | 'failed', nullable, required: How far the money Finero collected has got into your ERP, or null when Finero has collected nothing on this invoice. `held` means the connection pushes receipts manually and an admin has not released this one yet; `pending` means the push is queued and `processing` that it is in flight - under all three, the ERP has not been told yet. `posted` means the ERP accepted the receipt - Finero's part ends there, and what the ERP does with it afterwards (allocating it, or reversing it) is the ERP's business. `failed` means the receipt never reached the ERP, so your ERP still shows that money as owed until someone acts. Finero retries a `failed` push every 15 minutes for 24 hours when the ERP was simply unreachable; any other cause waits for a person, because retrying cannot fix it. The WORST state across the invoice's pushes is reported, because this field exists to surface a problem and a majority would hide one. NOT TO BE CONFUSED WITH a payment's `erp_push_status`: that one is a SINGLE payment's own push, while this rolls up every push on the invoice.
    - `collection_status` 'paid' | 'open' | 'inactive', required: ANSWER "HAS THIS INVOICE BEEN PAID?" FROM THIS FIELD. `paid` MEANS THE INVOICE IS PAID - nothing is left to collect on it - and it is the most current answer available: Finero knows the moment it collects, and your ERP finds out afterwards. `paid` REQUIRES TWO THINGS: Finero collected on it, AND no collection target has a balance outstanding. An invoice where Finero collected part and the remainder is excluded or otherwise blocked reads `inactive`, not `paid` — so `paid` can never hide money that is still owed. `open` means the invoice or a real installment is COLLECTIBLE by Finero — that, and nothing more. Whether a payment link or reminder actually goes out is a SEPARATE question, decided by which workflows this workspace has switched on, and no status on this invoice answers it. `inactive` is everything else. THE CONVERSE DOES NOT HOLD, and this is the one trap: NOT-`paid` does not mean unpaid. An invoice the customer settled directly with you, outside Finero, reads `inactive` - Finero did not take that money, so it cannot report having collected it. `paid` is conclusive; anything else means find out why. `paid` ALSO DOES NOT SAY HOW MUCH FINERO COLLECTED: an invoice settled by mixed paths - one installment direct to you, the rest through Finero - is still `paid`. Compare `amount_collected` against `total_amount` to attribute it. YOUR ERP LAGS THIS FIELD: it may still show a balance on a `paid` invoice until it applies Finero's receipt - NOT a reason to doubt the status. Read `erp_push_state` to tell ordinary lag from a push that will stay unreflected until someone acts. An invoice finalised with a balance still reads `inactive` when nothing on it can be collected - every installment excluded from collections, closed in your ERP, or the invoice has no billing email or a currency no connected payment provider can charge - and THE MONEY IS NOT WRITTEN OFF: `collection_outstanding` still carries it. Sum `collection_outstanding` for what is OWED - but it is populated on invoices nothing can be collected from, so filter to `collection_status=open` for what can actually be collected, and read each installment's `collectible` to see which parts. Invoice status blocks collection only when enabled on the connection; re-enabling requires fresh status. Other safeguards still apply. Inactive may also mean no balance outstanding, the ERP no longer has the invoice, or no payment schedule in installment mode. Invoice-only mode needs no schedule. A removed invoice can resume collection if a later sync finds it.
    - `has_active_payment_link` boolean, required: Whether a Finero payment link is currently active on any installment of this invoice. `false` on an open invoice is the worklist: something is owed and nothing has been sent to collect it. Filter on it rather than joining against the payment-link list.
    - `customer` object, required: Bill-to customer details embedded on the invoice. There is no customer ENDPOINT, but there is a stable customer KEY — see `id`.
      - `id` string, uuid, nullable, required: STABLE CUSTOMER KEY — group by this, never by name or email. Finero resolves each ERP customer into one row per (workspace, connection, ERP customer id), so this is the same value across every invoice for that customer. Name and email are NOT keys and fail in opposite directions: two different customers can share a name ("Globex Corporation #1" twice), and one customer can bill from several addresses. Null only on invoices created in Finero with no ERP customer behind them.
      - `number` string, nullable, required: The ERP's account key for the linked customer; id is Finero's generated UUID. For Oracle, this is the business account number: trimmed BillToCustomerNumber, preserving case and leading zeros and scoped to the workspace and ERP connection. For Xero, which has no customer account numbers, it is the contact's ContactID (a UUID, Xero's internal id) — an identifier, not something to show a person as an account number. Shared with Aging and receipt posting. Null when the invoice has no resolved account.
      - `name` string, nullable, required: The bill-to customer's name (for example a company). For Oracle, this is BillToCustomerName: the customer's party name, not the account's own name. Distinct from contact_name, which is a person.
      - `contact_name` string, nullable, required: The person named on the invoice as the bill-to contact. Display only: it is never used to identify anyone and nothing in Finero branches on it, because an ERP can carry two people with the same name on one account. Null when the ERP sends none, or when the workspace has switched the Contact name pull field off for this connector. For a sole trader it may equal name.
      - `email` string, nullable, required: Billing email the payment-link email is sent to.
    - `origin` 'local' | 'erp', required: Provenance / system of record: local = the invoice exists only in Finero; erp = an ERP connection owns (or will own) the record.
    - `connection_id` string, uuid, nullable, required: The exact ERP connection associated with this invoice.
    - `created_at` string, date-time, required: Creation time (ISO 8601 UTC).
    - `updated_at` string, date-time, required: Last update time (ISO 8601 UTC).
  - `pagination` object, required
    - `next_cursor` string, nullable, required: Opaque cursor for the next page — pass as ?cursor=. Null when there are no further results.
    - `has_more` boolean, required: Whether another page exists.
    - `limit` integer, required: The page size that was applied.
    - `total_count` integer: Total rows matching the filters, ignoring paging. Present ONLY when the request passed ?include_total=true.

## Other responses

- `400`: `invalid_cursor` — The cursor is malformed, was issued for a different query, or (aging) the report changed. Restart without cursor, keeping the filters identical. `validation_failed` — The request failed schema validation. See error.details for field messages.
- `401`: `invalid_credentials` — The credential is malformed or does not match an active key. The response never reveals whether a key identifier exists. `missing_credentials` — No Authorization: Bearer header was sent. `revoked_credentials` — The presented key was revoked. Create a new key in Settings → API.
- `403`: `feature_unavailable` — The tenant's tier does not currently include API access. Feature rollout flags cannot grant this entitlement. `permission_denied` — The key's permission does not allow this operation (readonly keys cannot call admin-only operations).
- `404`: `not_found` — No such resource in YOUR tenant. Ids belonging to another tenant are indistinguishable from missing ones.
- `429`: `rate_limit_exceeded` — Too many requests. Honor the Retry-After header (seconds) before retrying — waiting that long is enough. The RateLimit-* fields on every response say how much headroom is left before this happens; pace against them instead of retrying into a refusal.
- `500`: `internal_error` — Unexpected server error. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/getfinero/apis/finero-public-api.md) · [All operations](https://skmtc.dev/getfinero/apis/finero-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/getfinero/apis/finero-public-api/revisions/3d456e222775?raw)
