Skip to content

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.

  • 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.

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.

Terminal window
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:

{
"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.

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.

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.

Terminal window
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:

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

totalMicros is always subtotal + tax.

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.

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.

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.

  • 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.
If you want to… Read
Understand your own hlix bill instead Plans & pricing
Give the customer access to the work Client access
Get an approval you can bill an outcome against Deliverables & approvals
See every operation in the contract Client invoices