Client invoices
Client invoices operations in the Hlix API.
Client invoices are invoices an agency issues to its client accounts. These operations create drafts, issue and void invoices, render PDFs, open provider-hosted checkouts and record out-of-band settlements.
See the OpenAPI document for schemas and operation IDs.
Prerequisites
Section titled “Prerequisites”- Protected operations require an API key in
x-api-keyor a browser session cookie; some actions require a verified user session - Tenant-scoped operations use
X-Organization-Id; browser sessions can use their active workspace. Discovery and personal-workspace bootstrap do not require an active workspace - The base URL for your deployment,
https://server.hlix.aiby default
Operations
Section titled “Operations”| Method | Path | Operation |
|---|---|---|
GET |
/v1/api/client-billing/invoices |
List invoices |
POST |
/v1/api/client-billing/invoices |
Assemble a draft invoice from billables |
GET |
/v1/api/client-billing/invoices/{id} |
Get one invoice with its lines |
POST |
/v1/api/client-billing/invoices/{id}/issue |
Issue a draft, assigning its number |
GET |
/v1/api/client-billing/invoices/{id}/logo |
Download the logo frozen onto this invoice |
POST |
/v1/api/client-billing/invoices/{id}/pay |
Record an out-of-band settlement (bank transfer, cheque) |
POST |
/v1/api/client-billing/invoices/{id}/payment-link |
Open a provider-hosted checkout for an issued invoice |
GET |
/v1/api/client-billing/invoices/{id}/pdf |
Download the invoice as a PDF |
POST |
/v1/api/client-billing/invoices/{id}/void |
Withdraw an invoice, or discard a draft |
List invoices
Section titled “List invoices”GET /v1/api/client-billing/invoices · operation ID listClientInvoices
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
clientAccountId |
query | no | string | Only this customer’s invoices. |
status |
query | no | string | One of draft, final, void, paid. |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
X-Client-Portal |
header | no | string | The agency Workspace ID for a signed-in client’s portal requests. A verified user session and portal membership are required; API keys cannot authenticate portal access. This header does not grant agency administration access. |
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientInvoice[] | Invoice headers, newest first. lines is empty on this projection — read one invoice to get them. |
400 |
ApiError | The request named no active organization. |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | The resource does not exist, or the caller is a task-scoped credential and this endpoint is outside its allowlist. |
Assemble a draft invoice from billables
Section titled “Assemble a draft invoice from billables”POST /v1/api/client-billing/invoices · operation ID createClientInvoiceDraft
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
Request body — application/json, CreateInvoiceDraft (required)
| Property | Type | Required | Notes |
|---|---|---|---|
billableIds |
string[] | yes | |
buyerAddress |
string | yes | min length 1, max length 500 |
buyerBillingEmail |
string (email) | null | no | |
buyerLegalName |
string | no | min length 1, max length 200 |
dueAt |
string (date-time) | yes | |
paymentTerms |
string | no | min length 1, max length 200 |
replacesInvoiceId |
string | null | no | |
sellerAddress |
string | no | min length 1, max length 500 |
sellerLegalName |
string | no | min length 1, max length 200 |
taxRatesBps |
object | no |
Responses
| Status | Body | Description |
|---|---|---|
201 |
ClientInvoice | The draft, with its lines snapshotted from the ledger and its totals computed once and stored. |
400 |
ValidationError | ApiError | The JSON body failed schema validation (ValidationError), or the request named no active organization (ApiError). |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | A named billable or the client account is not this workspace’s. |
409 |
ApiError | The set cannot be invoiced: it spans two customers or two currencies, a charge nets to zero, a tax class has no rate, a correction’s charge was never invoiced, or the total would exceed what an invoice can represent. The message names which. |
422 |
ApiError | A database constraint refused the draft. |
Get one invoice with its lines
Section titled “Get one invoice with its lines”GET /v1/api/client-billing/invoices/{id} · operation ID getClientInvoice
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
X-Client-Portal |
header | no | string | The agency Workspace ID for a signed-in client’s portal requests. A verified user session and portal membership are required; API keys cannot authenticate portal access. This header does not grant agency administration access. |
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientInvoice | The invoice and every line it was built from. |
400 |
ApiError | The request named no active organization. |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
Issue a draft, assigning its number
Section titled “Issue a draft, assigning its number”POST /v1/api/client-billing/invoices/{id}/issue · operation ID issueClientInvoice
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
Request body — application/json, IssueInvoice (required)
The contract does not pin this body’s properties.
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientInvoice | The issued invoice. invoiceNumber and invoiceSequence are assigned by the database at this moment and are gapless per workspace. |
400 |
ValidationError | ApiError | The JSON body failed schema validation (ValidationError), or the request named no active organization (ApiError). |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
409 |
ApiError | Not issuable: already issued, no lines, the header does not reconcile with its lines, a charge on it is already invoiced, or a correction of one is missing from it. |
422 |
ApiError | A database constraint refused the issue. |
Download the logo frozen onto this invoice
Section titled “Download the logo frozen onto this invoice”GET /v1/api/client-billing/invoices/{id}/logo · operation ID getClientInvoiceLogo
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
X-Client-Portal |
header | no | string | The agency Workspace ID for a signed-in client’s portal requests. A verified user session and portal membership are required; API keys cannot authenticate portal access. This header does not grant agency administration access. |
Responses
| Status | Body | Description |
|---|---|---|
200 |
string (binary) | The agency logo frozen when the invoice was issued. Content-Type matches the format recorded on the invoice, with X-Content-Type-Options: nosniff. |
400 |
ApiError | The request named no active organization. |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice, or it carries no logo. |
Record an out-of-band settlement (bank transfer, cheque)
Section titled “Record an out-of-band settlement (bank transfer, cheque)”POST /v1/api/client-billing/invoices/{id}/pay · operation ID payClientInvoice
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
Request body — application/json, PayInvoice (required)
The contract does not pin this body’s properties.
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientInvoice | The invoice settled through an audited out-of-band payment recorded by an agency member. This is separate from provider-verified payment. Any open hosted checkout is cancelled to prevent a second payment through the provider. |
400 |
ValidationError | ApiError | The JSON body failed schema validation (ValidationError), or the request named no active organization (ApiError). |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
409 |
ApiError | Only an issued, unpaid invoice can be settled. |
422 |
ApiError | A database constraint refused the payment. |
Open a provider-hosted checkout for an issued invoice
Section titled “Open a provider-hosted checkout for an issued invoice”POST /v1/api/client-billing/invoices/{id}/payment-link · operation ID createClientInvoicePaymentLink
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
X-Client-Portal |
header | no | string | The agency Workspace ID for a signed-in client’s portal requests. A verified user session and portal membership are required; API keys cannot authenticate portal access. This header does not grant agency administration access. |
Request body — application/json, PaymentLink (required)
| Property | Type | Required | Notes |
|---|---|---|---|
successUrl |
string (uri) | no | max length 2000 |
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientPaymentLink | A provider-hosted checkout URL and its payment reference. Payment details are entered on the provider’s page and are not returned by this endpoint. Creating a checkout does not mark the invoice paid. Provider payments settle only after a signed webhook is reconciled against the invoice ID, amount and currency. An agency member can separately record an audited out-of-band settlement through POST /v1/api/client-billing/invoices/{id}/pay. |
400 |
ValidationError | ApiError | The JSON body failed schema validation (ValidationError), or the request named no active organization (ApiError). |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator attempting something other than reading or paying its own invoice. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
409 |
ApiError | Not payable: the invoice is a draft, void or already paid, it already has a checkout open with a different provider, or its total is above what the provider will take in one payment. |
501 |
ApiError | No payment provider is connected for this deployment. The invoice can still be issued, sent and paid outside hlix. |
Download the invoice as a PDF
Section titled “Download the invoice as a PDF”GET /v1/api/client-billing/invoices/{id}/pdf · operation ID getClientInvoicePdf
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
X-Client-Portal |
header | no | string | The agency Workspace ID for a signed-in client’s portal requests. A verified user session and portal membership are required; API keys cannot authenticate portal access. This header does not grant agency administration access. |
Responses
| Status | Body | Description |
|---|---|---|
200 |
string (binary) | The rendered invoice, every line included. |
400 |
ApiError | The request named no active organization. |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
409 |
ApiError | The invoice is a draft, or its stored totals no longer reconcile with its stored lines. Rendering a document that does not add up is refused rather than attempted. |
415 |
ApiError | The invoice is valid but this renderer cannot encode it — a party name or line description outside Latin-1. Retrying will not help; read the invoice through getClientInvoice instead. |
Withdraw an invoice, or discard a draft
Section titled “Withdraw an invoice, or discard a draft”POST /v1/api/client-billing/invoices/{id}/void · operation ID voidClientInvoice
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id |
path | yes | string | |
X-Organization-Id |
header | no | string | The workspace (organization) to act in. Omitted, the session’s active organization is used. |
Request body — application/json, VoidInvoice (required)
| Property | Type | Required | Notes |
|---|---|---|---|
reason |
string | yes | min length 1, max length 500 |
Responses
| Status | Body | Description |
|---|---|---|
200 |
ClientInvoice | The voided invoice. An issued invoice retains its number. To correct it, issue a replacement invoice referencing the original. |
400 |
ValidationError | ApiError | The JSON body failed schema validation (ValidationError), or the request named no active organization (ApiError). |
401 |
ApiError | No valid session or API key. |
403 |
ApiError | The caller is a client collaborator. Invoices are agency-only, reads included. |
404 |
ApiError | No such invoice in this workspace. Never a 403 — ‘forbidden’ would confirm that an invoice exists for a customer the caller was never shown. |
409 |
ApiError | The invoice is already void. |
422 |
ApiError | A database constraint refused the void. |
If a request fails
Section titled “If a request fails”The response table for each operation lists its documented errors. Common status codes include:
400— the body failed schema validation, or the request named no active organization. AValidationErrorbody carries the failing fields; anApiErrorbody carries onlyerror.401— no valid session or API key.403— authenticated, but not a member of the named organization, or a client collaborator without the required access.404— check the resource ID and your access to the selected Workspace.409— the expected revision or state is stale, or another operation currently owns the transition.500— the operation failed server-side. Retry only where an idempotency key makes that safe.