# Invoicing your client

**This is what you charge your customer.** Two records sit behind it: a **billable ledger** of individual charges, and the **invoices** you assemble from them and issue.

**These are different money:** Your own hlix plan — what you pay us — is [Plans & pricing](/billing/plans/) and lives on a separate surface entirely. The two are fully separate: a change to hlix's prices never moves what your customer owes, and what you charge your customer never reaches your own bill. Receipts under Settings are money you paid; invoices under Client billing are money you are owed.

## Prerequisites

- A **customer record** for the company you are billing, and the project assigned to it. A project with no customer cannot be billed.
- Your own **billing identity** — the supplier details that appear on the document you issue. Set it under Settings → Billing identity.
- An agency role. Every write here is agency-only.

## Record what you may bill

A billable is one charge. Three kinds exist, and they differ in what hlix reads for you versus what you state:

| Source | What it bills | What hlix reads from the source |
| --- | --- | --- |
| `agent_usage` | One completed agent run | The customer, the project, when the work happened, the tokens, and the model's rate |
| `outcome` | A published deliverable your customer approved | The customer, the project, and when they decided |
| `manual` | Anything else — a retainer, a fixed fee | Nothing. You name the customer, and the project if there is one. |

**For the first two, the customer comes from the project.** You cannot name a different one, so a project's work is always billed to that project's customer.

**The price is frozen when the charge is created.** For `agent_usage` the model's rate is recorded on the charge, so a later price change never alters what your customer was quoted. Your margin (`markupBps`) is recorded per charge, not as a hidden global setting.

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/client-billing/billables" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{"source": "agent_usage", "agentRunId": "…", "currency": "USD", "markupBps": 2000, "description": "Checkout redesign — agent time"}'
```

Expected output — the charge, with the rate it was priced from:

```json
{
  "id": "…",
  "entryType": "charge",
  "source": "agent_usage",
  "clientAccountId": "…",
  "projectId": "…",
  "description": "Checkout redesign — agent time",
  "quantity": "1.000000",
  "unit": "agent_run",
  "unitPriceMicros": 1284000,
  "amountMicros": 1284000,
  "currency": "USD",
  "occurredAt": "2026-08-27T15:58:02.000Z"
}
```

Money is held as integer **micros** — millionths of one currency unit — because a model call can cost a fraction of a cent. Rounding to a payable amount happens once, on the invoice.

An `agent_usage` charge is always **one** run: the tokens determine the price, not the quantity, so a run cannot be billed twice.

### Corrections append; nothing is edited

There is no edit and no delete. A mistake is corrected by appending:

- **`POST …/billables/{id}/adjust`** — a correcting entry naming the charge it corrects.
- **`POST …/billables/{id}/void`** — a reversal. A charge can be voided at most once.

The same source cannot be billed twice: one agent run, one cycle, one charge. A retried request is refused rather than billed again.

## Assemble and issue an invoice

An invoice's lines are **copies** of the charges, not references to them. Description, quantity, unit, price, amount, tax class and tax rate are copied onto the line when the draft is built, so a later adjustment, price change or renamed legal entity never alters a document your customer already holds.

| Status | Meaning |
| --- | --- |
| `draft` | Being assembled. The only state in which anything may change. |
| `final` | Issued. Numbered, dated, immutable, owed. |
| `paid` | Issued and settled. Still immutable. |
| `void` | Withdrawn — a discarded draft, or a withdrawn document that keeps its number. |

There is no `sent` or `overdue` status: neither is a fact about the document itself.

**Assemble a draft from the charges you name.** You list the billables; the customer and the currency come from them, not from you.

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/client-billing/invoices" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{
        "billableIds": ["…", "…"],
        "buyerAddress": "Acme B.V.\nKeizersgracht 1\n1015 Amsterdam",
        "dueAt": "2026-09-27T00:00:00.000Z",
        "taxRatesBps": {"standard": 2100}
      }'
```

`billableIds`, `buyerAddress` and `dueAt` are required. `taxRatesBps` supplies the rate for each rated tax class in basis points, so `2100` is 21%.

Expected output — a draft with no number yet:

```json
{
  "id": "…",
  "status": "draft",
  "invoiceNumber": null,
  "invoiceSequence": null,
  "currency": "EUR",
  "subtotalMicros": 4820000,
  "taxMicros": 916000,
  "totalMicros": 5736000
}
```

`totalMicros` is always `subtotal + tax`.
  **Issue it. hlix assigns the number.**

```bash
curl -sS -X POST "$HLIX_BASE_URL/v1/api/client-billing/invoices/$INVOICE_ID/issue" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -H 'content-type: application/json' \
  -d '{}'
```

Expected output:

```json
{"id": "…", "status": "final", "invoiceNumber": "2026-0007", "invoiceSequence": 7, "issuedAt": "2026-08-28T08:02:11.000Z"}
```

Numbers come from a per-Workspace sequence that never collides and stays **gapless**: an issue that fails gives its number back. A voided invoice keeps its number for the same reason, because a gap in an invoice sequence reads to a tax authority as a deleted document.
  **Hand it over, then record how it was paid.**

```bash
curl -sS "$HLIX_BASE_URL/v1/api/client-billing/invoices/$INVOICE_ID/pdf" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID" \
  -o invoice.pdf
```

Expected result: a PDF written to `invoice.pdf`, rendered from the invoice's lines.

For a card payment, open a hosted checkout for the issued invoice with `POST …/payment-link`; for a bank transfer or cheque, record the settlement out of band with `POST …/pay`. Either way the invoice moves to `paid` and stays immutable.
  ### Correcting an issued invoice

You do not. Apart from its status, an issued invoice never changes.

To correct one, **void it with a reason, then issue a replacement that names the original.** The replacement points at the original, never the other way round, so the original stays exactly as issued.

## Tax

Each line carries a tax class, recorded on the document:

- **`standard` and `reduced`** are real rates that differ by jurisdiction, so you state the rate per invoice.
- **`zero`, `exempt` and `reverse_charge`** are zero-rated by definition and take no rate — respectively 0%, outside the tax's scope, and liability moved to the customer.

The total is rounded to the currency's minor units exactly once, and the rounding rule is recorded on the invoice.

## Your identity on the document

The supplier details you set under Settings → Billing identity appear on every invoice you issue. Your logo and identity are placed on the document when your Workspace has an **active subscription**; without one the invoice is unbranded, and it is still complete and correct.

Whether your branding appears is decided once, when the invoice is issued. If your subscription status cannot be confirmed at that moment, hlix includes your branding.

## If a billing action fails

- **`403` with `{"error": "Client accounts are agency-only"}`** — a client collaborator touched the customer records.
- **`403` with `{"error": "Only the agency can change an invoice"}`** — a client attempted an invoice write.
- **`404` with `{"error": "Client account not found"}`** or **`{"error": "Invoice not found"}`** — not in this Workspace, or not visible to this caller. As everywhere in hlix, do not read a `404` as proof of absence.
- **`Project … is not assigned to a client account — assign one before billing its work`** — assign the project to a customer first. Without one there is nobody to bill.
- **`Agent run … is <status> and has not finished — its token counts are not final`** — bill a completed run. An in-flight run's numbers can still move.
- **`Agent run … is not attributed to a project, so there is no customer to bill`** — the run has no project, so no customer can be derived.
- **`Agent usage is priced from a USD catalog and cannot be billed as EUR — no exchange rate is recorded`** — agent usage bills in USD. Use a `manual` charge if you need another currency.
- **A charge could not be priced** — the model has no rate in the catalog, or the run's token counts are invalid. The error says which.
- **`409` on creating a charge** — the same source has already been billed. One run, one charge.
- **`409` with `{"error": "That portal slug is already taken."}`** — another customer in this Workspace uses that handle.
- **Deleting a customer fails** — it still has projects or charges, and removing it would orphan delivery history. Set its status to `archived` instead.
- **`400` on `PUT` of your billing identity** — a field the request does not accept, or an address that fails validation.

## Where to go next

| If you want to… | Read |
| --- | --- |
| Understand your own hlix bill instead | [Plans & pricing](/billing/plans/) |
| Give the customer access to the work | [Client access](/clients/access/) |
| Get an approval you can bill an outcome against | [Deliverables & approvals](/clients/deliverables/) |
| See every operation in the contract | [Client invoices](/api/reference/client-invoices/) |

## Next steps

[Plans & pricing](/billing/plans/)
  [Deliverables & approvals](/clients/deliverables/)
  [Client billing](/api/reference/client-billing/)
  [Client invoices](/api/reference/client-invoices/)