---
title: "Get an invoice with its installments"
method: GET
path: "/v1/invoices/{invoiceId}"
tags: ["Invoices"]
---

# Get an invoice with its installments

`GET /v1/invoices/{invoiceId}`

## Request

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

Returns one invoice including its installments (ordered by sequence). Use an installment's id to create a payment link. Returns not_found for ids outside your tenant.

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

## Path parameters

- `invoiceId` string, uuid, required

## Response `200`

Success

- object
  - `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 invoice is not final in your ERP (a draft, or awaiting approval) or the ERP has no amount for it yet: nothing is owed until it is final, 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).
  - `installments` object[], required: The invoice's installments, ordered by sequence.
    - `id` string, uuid, required: Installment id — use as installment_id when creating a payment link.
    - `sequence` integer, required: 1-based installment sequence within the invoice.
    - `original_amount` string, required: Original installment amount. Exact decimal string at the CURRENCY'S own scale — USD "1250.00", JPY "1250", BHD "1250.000". Never parse as float for arithmetic.
    - `due_date` string, date, nullable, required: Installment due date (YYYY-MM-DD).
    - `collection_status` 'paid' | 'open' | 'inactive', required: What Finero is doing about collecting THIS installment. Same three values as the invoice's `collection_status`, and it inherits that verdict: an installment of an `inactive` invoice is `inactive`. `paid` MEANS THIS INSTALLMENT IS PAID - nothing is left on it - and it is the current answer even while your ERP still shows a balance, which lags. The converse does not hold: an installment settled directly in your ERP reads `inactive`, because Finero did not take that money, so NOT-`paid` is not the same as unpaid. `open` requires THREE things together: an outstanding balance, `collectible` being true, and the ERP's own status saying the installment is still open - each connector declares which of its status values mean that. Where there is no provider status to judge (an invoice created in Finero) the first two decide alone. IT REPORTS WHAT FINERO IS DOING, NOT WHAT IS OWED: an installment that is genuinely outstanding but blocked - excluded, no billing email, a currency no connected provider can charge - reads `inactive`, because Finero is not collecting it. The money has not been written off; `collection_outstanding` still carries it, and `block_reasons` says why.
    - `collection_outstanding` string, nullable, required: What is still outstanding on this installment, as an exact decimal string. Accounts for Finero payments the ERP has not been told about yet. Follows its invoice: null while the invoice is not final in your ERP, zero once the invoice is no longer present there. It is what is OWED, not what is collectible: it stays non-zero when `collectible` is false. Check `collectible` and `block_reasons` before treating it as money you can ask for.
    - `amount_collected` string, required: How much Finero has confirmed collected on this installment, as an exact decimal string. Money taken through a Finero payment link only; an installment settled directly in your ERP leaves this at zero. It reports what Finero collected AGAINST THIS INSTALLMENT, which is not necessarily where your ERP applied it — the ERP allocates across the whole invoice. `list_payments` records where Finero collected.
    - `collectible` boolean, required: Whether Finero considers this installment collectible right now. False once there is nothing left to collect, and also for installments blocked by an exclusion, a non-final invoice, a missing billing email, or an invoice that is no longer present in your ERP.
    - `block_reasons` string[], required: WHY this installment is not collectible, as stable codes — empty when it is. Invoice-level blocks propagate here, so this answers the question without a second lookup. One code is derived from the installment's own facts rather than stored: `excluded_from_collections` when that flag is set — the same derivation the Collections board makes, so the two surfaces name the same cause. Plain-English meanings for every code are published at https://app.getfinero.com/guide, and the workflows catalogue returns the same dictionary in full - every code with its label, what it means and what resolves it.
    - `excluded_from_collections` boolean, required: Manually excluded from collections.
    - `created_at` string, date-time, required: Creation time (ISO 8601 UTC).
    - `updated_at` string, date-time, required: Last update time (ISO 8601 UTC).

## Other responses

- `400`: `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.

## Changes

- **2026-10-20** `d17186951474`: 1 breaking, 12 warning
  - the response property `installments/items/collection_outstanding` became nullable for the status `200`
  - added the new `link_already_covered` enum value to the `error/code` response property for the response status `400`
  - added the new `link_already_covered` enum value to the `error/code` response property for the response status `401`
  - added the new `link_already_covered` enum value to the `error/code` response property for the response status `403`
  - …9 more

[Operation history](https://skmtc.dev/getfinero/apis/finero-public-api/changes/v1/invoices/:invoiceId/get.md)

---

[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/d17186951474?raw)
