Finalize Invoice
Finalizes a DRAFT invoice — the invoice.finalized action: the draft’s
charges post to the ledger, its derived status flips off draft, and any
draftPayments annex carried since
create is applied as real
payments in the same transaction. The invoice keeps its id and number — a
draft becomes a live invoice in place. Returns the refreshed document (the
posted invoice row and its now-materialized payments).
Precondition (422 INVOICE_NOT_DRAFT). The target must be a draft;
finalizing a live invoice is rejected.
Concurrency + idempotency. Requires If-Match (the draft’s current
headJournalId); the body carries the client-minted actionId. An
identical retry replays the original outcome — the finalized invoice — and
never re-posts or double-applies the annex.
Required permission: company.payment:update
Authorizations
API key authentication. Send your raw API key as the Authorization header value with NO scheme prefix — Authorization: YOUR-API-KEY. Do NOT prefix it with Bearer or ApiKey, and do not use an X-API-Key header; those are not accepted.
Headers
The invoice's current headJournalId — the optimistic-concurrency watermark every single-invoice write after creation must send. Read it off any invoice read or write response and echo it verbatim (a bare uuid; an entity-tag dressing of it — "uuid" or W/"uuid" — is also accepted). Missing or malformed is a 400 (IF_MATCH_REQUIRED / IF_MATCH_INVALID); a stale value is a 409 IF_MATCH_CONFLICT whose body carries the current invoice. An idempotent actionId replay short-circuits BEFORE the watermark is evaluated.
Path Parameters
Company identifier
Invoice identifier
Body
Client-minted idempotency key — becomes the finalize action's journal id. An identical retry replays the original outcome; reuse with a different payload is 409 ACTION_ID_REUSED
Optional display label for the source system's author (e.g. the integrator-side user). Stamped as the journal record's display attribution; the acting principal stays the External API service user, so a label can never impersonate an in-app user. Ignored on idempotent replays
1 - 255Response
The finalized invoice — refreshed read state (posted, status no longer draft) with the annex materialized as real payments
The response of every single-invoice write — refreshed read state, not an ack: the emitted journal id(s), THE invoice row (identical shape to the reads — one invoice representation everywhere; its headJournalId is the next If-Match), and the invoice's live payments. An idempotent actionId replay returns this same shape rebuilt from the original outcome, server-minted values included.
Every journal id the write emitted — the anchor action's id (the actionId you supplied) first, then any engine-minted siblings (a multi-mark payment's additional marks) and any companion the horizon rule composed (e.g. the reserve unwind of a pre-horizon eroding payment's removal, or a delete's payment sweep)
1THE invoice representation — the same shape everywhere an endpoint returns an invoice (listing rows, the detail read, and every write's refreshed-row response). headJournalId is the invoice's current journal head — the optimistic-concurrency token subsequent writes echo back as If-Match.
The invoice's live payment marks after the write, newest first
