Reconcile the requested token amount with received and confirmed totals at an address you control, including partial payments and overpayments. Vilna observes incoming transactions and updates the invoice's amounts and status. The payer signs and sends from their own wallet, directly to yours. See the integration patterns for the surrounding workflow and the Non-custodial Service Notice.
Use a project API key with api:invoice:read and api:invoice:write. Register the merchant-controlled address first.
5 lifecycle states Received + confirmed totals Public invoice view Exclusive payment deadline
status is the lifecycle. Amounts describe the current payment facts independently:
| Status | Meaning |
|---|---|
| open | The payment window is open. The invoice can confirm before the deadline. |
| processing | The window ended; payment checks, confirmations or operator handling are still pending. |
| confirmed | Enough of the requested token amount was confirmed. Terminal. |
| cancelled | Cancelled under the rules below. Terminal. |
| expired | The window ended, checks completed and no valid payments were found. Terminal. |
May also be reached directly from open when enough payments confirm before the deadline.
Requires the cancellation checks below; partial payments stay linked to this invoice.
Reached from processing only after the checks complete with no valid payments.
The payment window starts at created_at and ends just before expires_at, or earlier if the invoice becomes confirmed or cancelled. Eligibility follows the transaction's native inclusion time, not the time your webhook arrived. An eligible payment can finish confirming after the deadline. Reaching the deadline alone does not mean expired; partial payment can leave the invoice in processing.
amount is the requested amount, received_amount is the total from currently valid eligible payments in the expected token, and confirmed_amount is the confirmed portion. All three are base-unit integer strings in the authenticated API. A reorganization can reduce the totals. A terminal lifecycle decision stays terminal even if later chain facts change; reconcile current amounts and transaction links before taking further action in your application.
Use POST /invoices - create an invoice. Provide a registered address, CAIP-19 asset_gid, amount in base units and a future expires_at.
Invoice payment windows at one address cannot overlap. If an invoice at that address is still accepting payments, the same asset and amount return the existing invoice with 200; a different asset or amount returns 409 Conflict. A 200 response does not update its expiry or metadata. Check the returned ID, expiry and metadata before associating it with an order.
Create the Idempotency-Key and expiry once, then save both with the full request body. Retries reuse the exact key and body. For a token with 6 decimals, 42.5 units is "42500000" in base units. Read metadata for the exact chain and contract before choosing the amount; a symbol does not determine decimals.
For an uncertain result, retry the same key and body. If you know the invoice ID, read its current state; otherwise, identifying the result depends on available lists and filters. Do not automatically create a fresh key. See Idempotency.
Save the returned item.id to track the invoice and associate it with your order.
status_logs records lifecycle transitions with status, nullable comment and changed_at. It is not a history of every amount update. metadata is merchant-only; decoded keys and values together may occupy at most 4096 UTF-8 bytes.
The public API view requires no authentication. Anyone with the invoice UUID can read it, so share the link only with its intended recipients. Use GET /public/invoices/{invoice_id} - public invoice to build your own informational payment page.
This response uses PublicInvoice, whose amount, received_amount and confirmed_amount each have base and an optional formatted string. Use the formatted value when present; otherwise label the base-unit value as such. Do not append a hard-coded token symbol. The public view omits merchant metadata and status comments. It differs from authenticated Invoice, where the three amount fields are strings.
Read GET /invoices/{invoice_id} - invoice details as the authority for completion; a transaction notification is a reason to refresh it, not proof that the invoice is confirmed.
Use the token's metadata decimals to format nonnegative invoice amounts. Keep the integer value exact, including values above JavaScript's safe-integer limit. If metadata is missing, show the raw base units and asset id rather than guessing decimals.
Inspect item.transactions alongside the totals. is_active says the transaction is still current on its chain; it does not mean it paid the invoice. A Bitcoin mempool candidate can be active with no credited amount. Deposits are net positive contributions per asset; is_matched identifies the expected token. Other assets do not count toward the requested amount.
On a reorganization or replacement, a retained link becomes inactive and its deposits empty. The association remains, so the same transfer cannot pay another invoice. Active transaction summaries are in references.transactions[chain_gid][txid]; inactive links have no summary there. These summaries use details.family and its family-specific fields.
Compare base-unit amounts using BigInt. For a request of "42500000" at 6 decimals, "20000000" received is a partial 20 units; "45000000" received is 45 units, an excess of 2.5. More than enough received does not imply enough confirmed, and a cancelled or expired invoice is not complete.
There is no public manual-confirm action. Read the current status, received_amount, confirmed_amount and transaction links rather than assigning an application payment category to the API response.
Subscribe to transactions at the invoice address and re-read the invoice when a notification arrives. Subscriptions do not send reorganization corrections. See Events and use the existing outage reconciliation workflow when deliveries are interrupted.
Use GET /invoices - list invoices. Filter by lifecycle status; repeat the parameter for alternatives (up to 10 values). Compare totals in your application if you need to identify partial payment or excess.
The list returns InvoiceSummary, without status_logs and transactions. Read the individual invoice for details.
You can cancel an open or processing invoice when no recorded valid payment remains unconfirmed and the confirmed total is below amount. A fully confirmed partial payment does not prevent cancellation. A failed cancellation precondition returns 422.
Call POST /invoices/{invoice_id}/actions/cancel - cancel an invoice. Use a separate intent key for cancellation and save the key, invoice id and optional body for retries.
Success returns 204 No Content; cancelling an already-cancelled invoice also returns 204. The comment is optional, at most 64 characters; the body may be empty or omitted. Cancelling changes the monitoring lifecycle and does not move or return funds.
After cancellation, no new payments are linked to the invoice, even if their block time falls within its former payment window. Existing payment links remain, and the invoice's received_amount and confirmed_amount can still change as chain data changes. Its status remains cancelled. Linked payments are not transferred to a new invoice, and the address can be reused.
To reuse the address, create a new invoice under the creation requirements and with a new Idempotency-Key. The new invoice has its own payment window.