curl -X POST https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/finalize \
-H "Authorization: Bearer $INVOICE_AI_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import InvoiceAI from '@horizonpay/invoice-ai'
const invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY
// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.
const invoice = await invoiceai.invoices.finalize('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')
console.log(invoice.number)from invoice_ai import InvoiceAI
client = InvoiceAI() # reads INVOICE_AI_API_KEY
# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.
invoice = client.invoices.finalize("in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8")
print(invoice.number)Finalize an invoice
Issues a draft: assigns the next number in your series (e.g. INV-0042) and moves it to open. The draft needs at least one line. Finalizing an invoice that already has a number returns it unchanged, so a retry never spends a second number. Does not email the customer — see /send. Emits invoice.finalized.
Scope: invoices:finalize
Idempotency: Idempotency-Key required (428 without it). A retry with the same key and body replays the first response (Idempotent-Replayed: true); the same key with a different body is a 422 idempotency_mismatch.
curl -X POST https://invoice.horizonpay.co/api/v1/invoices/in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8/finalize \
-H "Authorization: Bearer $INVOICE_AI_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import InvoiceAI from '@horizonpay/invoice-ai'
const invoiceai = new InvoiceAI() // reads INVOICE_AI_API_KEY
// Retries reuse one Idempotency-Key; pass { idempotencyKey } to set your own.
const invoice = await invoiceai.invoices.finalize('in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8')
console.log(invoice.number)from invoice_ai import InvoiceAI
client = InvoiceAI() # reads INVOICE_AI_API_KEY
# Retries reuse one Idempotency-Key; pass idempotency_key=... to set your own.
invoice = client.invoices.finalize("in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8")
print(invoice.number)Authorizations
An Invoice-AI API key sent as Authorization: Bearer inv_live_….
Create keys in Settings → API keys; the secret is shown once. Each key carries scopes, and every operation lists the scope it needs (x-required-scope):
business:read— Read your business profile, tax ID and bank detailsclients:read— List and read your clientsclients:write— Create, update and archive clientsproducts:read— List and read products and pricesproducts:write— Create, update and archive products and pricesinvoices:read— List and read invoices, including PDFsinvoices:write— Create, edit and delete draftsinvoices:finalize— Finalize invoices and void theminvoices:send— Email invoices to your clientspayments:write— Mark invoices as paidwebhooks:manage— Manage webhook endpoints
Keys cannot be created or revoked through the API, so a leaked key cannot mint more keys.
Headers
A unique key per distinct operation (a UUID works), reused only when retrying that same request. Up to 255 characters; stored for 24 hours.
255"6f1c2d9e-8a4b-4c3f-9e7d-2b5a1c8f4e30"
Path Parameters
The draft, in_… or UUID.
"in_Pb2Xk7Mv4Qs9Lr1Wd6Tn3Fh8"
Response
The finalized invoice, with its number and lines.
The finalized invoice.
Show child attributes
Show child attributes