Invoices API
List, create, update, summarize, and manage recurring invoices through public API v1.
Summary
Invoice operations use invoices.read or invoices.write. Eigenn scopes every invoice operation to the authenticated team.
Capabilities
Invoice Endpoints
| Method | Endpoint | Scope | Purpose |
|---|---|---|---|
| GET | /invoices | invoices.read | List and filter invoices |
| POST | /invoices | invoices.write | Create, create and send, or schedule an invoice |
| GET | /invoices/payment-status | invoices.read | Read team payment-health score |
| GET | /invoices/summary | invoices.read | Summarize selected invoice statuses |
| GET | /invoices/{id} | invoices.read | Retrieve one invoice |
| PUT | /invoices/{id} | invoices.write | Update status, paid time, or internal note |
| DELETE | /invoices/{id} | invoices.write | Delete a draft or canceled invoice |
| GET | /files/download/invoice | invoices.read with id; none with token | Download an invoice or receipt PDF |
There is no separate public POST /invoices/{id}/send operation. You set the email behavior with deliveryType when you create the invoice.
Prerequisites
You must have a valid bearer token with the invoices.read and/or invoices.write scope. Ensure you are operating within an authenticated team context. Customers must exist in your team before you can issue invoices to them.
Concepts
Invoices represent individual or recurring requests for payment. Each invoice is tied to a customer and can have various statuses such as unpaid, paid, draft, scheduled, or canceled. Recurring invoice series automate the creation of invoices on a set schedule, and generated invoices remain as separate records if the series is paused or deleted. Invoice creation can include sending or scheduling email delivery. Idempotency keys provide bounded replay protection for successful writes; inspect invoice state after a failed or uncertain request.
Workflow
List Invoices
GET /invoices supports cursor pagination with pageSize from 1 to 100.
Filters include:
- Search text
- Customer IDs
- Invoice statuses
- Issue, due, and sent date ranges
- Amount, tax, and VAT ranges
- Recurring state or series IDs
- Sort tuple
curl --request GET \
--url "https://api.eigenn.io/v1/invoices?pageSize=25" \
--header "Authorization: Bearer $EIGENN_API_TOKEN"The returned records can include calculated totals, customer details, status dates, and PDF or preview URLs when a token exists.
Create an Invoice
POST /invoices needs:
- customerId
- deliveryType
- dueDate
- issueDate
- lineItems, with at least one item
- template
deliveryType accepts:
| Value | Result |
|---|---|
| create | Finalize immediately as unpaid without the send action |
| create_and_send | Finalize as unpaid and start customer email delivery |
| scheduled | Schedule future work at scheduledAt |
scheduledAt must be in the future for scheduled delivery. If you do not supply invoiceNumber, Eigenn generates the next sequential number. If you supply a number that is already in use, Eigenn returns 409.
issueDate and dueDate take an ISO 8601 date, such as 2026-06-01, or a date-time, such as 2026-06-01T09:30:00Z or 2026-06-01T09:30:00+02:00. Include Z or a UTC offset when the time of day matters. An empty string sets the issue date to today and the due date to one month from today. Any other value returns 400, including words such as now and slash dates such as 01/06/2026, whose day and month order is ambiguous.
Use the OpenAPI explorer or the generated SDK model for the complete template and line-item structure. Amounts and line prices use major currency units, such as 125.50, rather than payment-provider minor units. Line-item names and rich-text fields use the documented editor-content structures; returned content fields can be serialized JSON strings.
How Eigenn prices an invoice
Eigenn calculates the invoice's amount, subtotal, tax, and VAT from its line items, discount, and template tax settings, the same way the application does. It stores those figures, and Pay Now charges the stored amount less any payments. The request's amount, tax, and vat fields are accepted so existing clients keep working, but Eigenn ignores them. Read the calculated figures from GET /invoices/{id}.
The template's tax settings are includeTax, taxRate, includeVat, vatRate, includeLineItemTax, taxInclusiveMode, enableMultipleTaxes, and tax2Rate; a line item can carry tax and tax2 rates. When the template leaves out includeTax or includeVat, Eigenn applies that tax at the template's rate, which is zero when no rate is given. Eigenn stores the settings it used with the invoice, so the PDF and the invoice page show the same figures.
Line prices and the discount must be zero or more with at most two decimal places, and tax rates must be between 0 and 100. Each stored figure, and the discount, must not exceed 999,999,999,999.99. A request outside these limits returns 400.
The create schema accepts a line item's productId, but the current creation handler does not retain that link. Do not rely on API-created invoices for catalog-product or variant revenue attribution.
The creation response returns the ID, the status, timestamps, and PDF or preview URLs when they are available. Delivery can continue after Eigenn finalizes the invoice. An unpaid response alone does not prove that the email is complete.
Eigenn checks the schedule, the dates, the customer, the line items, and the amounts before it stores anything. A 400, 403, or 404 response means Eigenn created no invoice, used no invoice number, and queued no delivery. A failure after the invoice is stored, such as a 500 while queueing delivery or a lost response, can still leave an invoice. Use a stable invoice number for reconciliation, and inspect the team's existing invoices before you retry such an error. Error responses are not cached for idempotent replay.
Retrieve and Update
GET /invoices/{id} can include recurring information when you request includeRecurring.
PUT /invoices/{id} accepts:
- internalNote
- paidAt
- status
The request schema accepts paid, canceled, unpaid, scheduled and draft, but the manual transition rules allow only unpaid/overdue → paid, paid/canceled → unpaid, and draft/unpaid/overdue → canceled. Invalid and repeated status transitions return 409. Use the delivery path for draft/scheduled transitions; this endpoint cannot create or cancel delivery jobs.
Marking paid sets paidAt to the supplied value or current time and books the remaining balance as a successful manual payment in the same transaction. Reopening clears paidAt and cancels only payments created by Mark as paid. Provider and separately entered payments remain. These operations do not charge or refund a payment method. Applicable approval policies are enforced on this path.
Delete
DELETE /invoices/{id} applies only to draft and canceled invoices. Cancel an eligible non-draft invoice before you delete it.
When you delete an invoice, you do not delete its customer.
Summary and Payment Status
GET /invoices/summary optionally filters by statuses and returns a team total with currency breakdown information. Missing exchange rates fall back to 1:1; inspect the breakdown before treating a mixed-currency total as a converted accounting value.
GET /invoices/payment-status returns one team-level object with score and paymentStatus. It has no cursor pagination or page-size parameters and does not return individual payment records. Retrieve an invoice by ID to inspect that invoice's status.
Download an Invoice or Receipt PDF
GET /files/download/invoice returns the rendered PDF. Identify the invoice in one of two ways:
id: the invoice ID. Send a bearer token with invoices.read. Eigenn returns only invoices in the authenticated team.token: the token from the invoice's public link. No bearer token is needed. A draft invoice's token returns 404. An expired link still works while the invoice is unpaid or overdue and the token is the invoice's current one.
| Parameter | Effect |
|---|---|
| type=receipt | Returns the receipt instead of the invoice. Only paid invoices have a receipt; other statuses return 400. |
| preview=true | Returns the PDF for inline display, without an attachment Content-Disposition header. |
curl --request GET \
--url "https://api.eigenn.io/v1/files/download/invoice?id=$INVOICE_ID" \
--header "Authorization: Bearer $EIGENN_API_TOKEN" \
--output invoice.pdfRecurring Invoice Endpoints
| Method | Endpoint | Scope | Purpose |
|---|---|---|---|
| GET | /invoice-recurring | invoices.read | List recurring series |
| POST | /invoice-recurring | invoices.write | Create a series |
| GET | /invoice-recurring/{id} | invoices.read | Retrieve a series |
| PUT | /invoice-recurring/{id} | invoices.write | Update a series |
| DELETE | /invoice-recurring/{id} | invoices.write | Delete a series |
| POST | /invoice-recurring/{id}/pause | invoices.write | Pause generation |
| POST | /invoice-recurring/{id}/resume | invoices.write | Resume generation |
| GET | /invoice-recurring/{id}/upcoming | invoices.read | Preview the next invoices |
When you delete a recurring series, Eigenn cancels the future scheduled work and returns the scheduled invoices to draft. The invoices that Eigenn generated before remain independent records.
When you pause a series, Eigenn stops future generation and returns the already scheduled invoices to draft. You can resume only a paused series.
A series' line items follow the same limits as invoice line items: prices must be zero or more with at most two decimal places, and the tax and tax2 rates must be between 0 and 100. A create or update request outside these limits returns 400 and changes nothing. A series saved before these limits applied can still be retrieved, listed, paused, and updated; send corrected lineItems to fix its lines.
Behavior specification
Billing restrictions
Customer-invoice POST, PUT, and DELETE operations return 402 with code: "BILLING_WRITE_BLOCKED" when workspace billing is read-only. Recurring-series creation, update, resume, and deletion follow the same rule. Pausing a recurring series remains available with the required scope. Read requests remain available.
Active and trialing subscriptions permit writes, as does past-due billing within its seven-day grace period. No subscription, an expired grace period, or unpaid, paused, canceled, incomplete, or expired incomplete status blocks writes. Resolve the workspace subscription before retrying; a billing refusal does not persist the requested change. See Billing and Usage.
Idempotency
Authenticated invoice writes accept an optional Idempotency-Key of at most 128 characters.
Use a stable key for one logical create or update. Successful responses are cached for 24 hours, scoped to the authenticated identity, method, path, query, and key. For current cached responses, the guard compares a hash of the exact request body and returns 422 if it differs; even JSON whitespace or field order can matter. Older cache entries without a body hash can still replay their original response. Use one key for one unchanged request.
A request still in progress can return 409 with Retry-After. An unavailable replay guard can return 503. Replay protection is not an exactly-once guarantee, particularly after errors or cache failures. Check the invoice before retrying an uncertain create-and-send request.
PDF Download File Names
A PDF download names the file {invoiceNumber}.pdf, or receipt-{invoiceNumber}.pdf for a receipt, in two Content-Disposition parameters:
filename*carries the name in UTF-8, so an invoice number with non-Latin characters, quotes, or emoji arrives exactly as written. Browsers and other clients that follow RFC 6266 use this parameter.filenameis an ASCII fallback for clients that ignorefilename*. Every character other than ASCII letters, digits,.,_,-, and spaces becomes_, and runs of_collapse into one. If no ASCII letter or digit remains, the fallback isfile.
In both parameters, control characters, /, and \ become _, and the name is cut to 200 UTF-16 code units. For invoice number №12 "Q3", the header is:
Content-Disposition: attachment; filename="_12 _Q3_.pdf"; filename*=UTF-8''%E2%84%9612%20%22Q3%22.pdfRead filename* when you save downloads from your own code. The generated Python SDK reads only filename and stops at the first space or quote. PDF downloads are sent with Cache-Control: no-store, max-age=0.
Common Errors
| Status | Cause |
|---|---|
| 400 | Invalid schedule, dates, line items, amounts, invoice number, status, or deletion state |
| 401 | Missing or invalid bearer token |
| 402 | Workspace billing prevents writes |
| 403 | Missing invoices.read or invoices.write |
| 404 | Invoice or customer not found in the team; or an invalid, draft, or no-longer-usable invoice link token |
| 409 | Invoice number, current state conflict, or matching request still in progress |
| 422 | Request structure is invalid |
| 429 | Resource limit exceeded |
| 500 | Invoice creation or subsequent processing failed; inspect for a persisted invoice |
| 503 | Idempotency guard unavailable; follow Retry-After |
Diagrams
Rendering diagram…
Screenshots
Not applicable: this page describes an API or a non-visual workflow rather than an application screen.
Verification
- Authenticate with a bearer token and list invoices; expect filtered invoice data and metadata.
- Create an invoice with valid data and deliveryType; expect a response with the invoice ID, status, and possible PDF/preview URLs. Retrieve it; expect the amount, subtotal, tax, and VAT calculated from its line items, whatever amount the request declared.
- Create a scheduled invoice with a past scheduledAt, or any invoice with dueDate
2026-02-30; expect 400 and no new invoice in the list. - Replay a successful creation with the same key and unchanged request within 24 hours; expect the cached response. For a failed request, inspect persisted invoices before any retry.
- Request summary and payment-status endpoints; expect aggregate totals and a single team payment-health object, respectively. Inspect an individual invoice through its ID.
- Create and then pause a recurring series; expect scheduled invoices moved to draft.
- Attempt to delete an invoice that is not draft or canceled; expect an error response.
- Attempt any invoice action without appropriate scope or a valid token; expect 401 or 403 error responses.