Billing period closes → one usage report per account

Your product already counts everything. The customer’s finance team wants it on one page they can argue with.

Trigger → artefact

A billing period closes, or a customer clicks Exporta usage report per account, with every amount derived from the counters

Every metered product hits the same week: the counters are correct, the dashboard is fine, and then someone in finance asks for the period as a document — with the allowance, the overage, the rate and the total on one page. The export button ships as a CSV, and the dispute starts there.

Here the caller sends the meter readings and the plan. The document works out what went past each allowance, prices it at the rate printed on the row, applies the adjustments, tops up to a contracted minimum if there is one, and adds the tax. Send a total of your own and the render is refused with the field named — because a total computed somewhere else is the one the customer will not accept.

Built with the HTML API. Need a designed image or certificate instead? Use the Canvas API — same data, same free year.

A SaaS usage report PDF rendered by PixlDocs, showing metered usage, overage and the derived total
Usage report — rendered by the template this page calls.

What ships in this category

The documents, and the part of each that is hard.

A SaaS usage report PDF rendered by PixlDocs, showing metered usage, overage and the derived total

Usage report

Meter-by-meter allowance, usage, utilisation, billable quantity and rate; adjustments and credits; shortfall to a contracted minimum; tax and the total for the period — with usage attributed by project underneath.

Hard part The billable quantity beyond each allowance, the charge on every row, the commit shortfall and the total — never sent by the caller.

template_id 238bb9b8-ef48-4c33-85cb-14a8b3bf8118

A subscription renewal notice PDF rendered by PixlDocs, showing the amount, renewal date and cancellation link

Renewal notice

The advance notice a subscription is required to send before it charges: the amount, the date, the card it will be taken from, what is being charged for, and how to cancel before then.

Hard part The charge stated before it happens — amount, date and payment method on one line the customer cannot miss.

template_id d9b7cf93-4885-46d2-b501-d196ca117583

The whole integration

One call. Named fields. No SDK to install.

the call your product makesbash
# once per account, when the billing period closes
curl https://api.pixldocs.com/v1/render \
  -H "Authorization: Bearer $PIXLDOCS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "238bb9b8-ef48-4c33-85cb-14a8b3bf8118",
    "format": "pdf",
    "data": {
      "account_name": "Meridian Advisory LLP",
      "plan_name": "Scale, annual",
      "plan_fee": 499,
      "tax_percent": 18,
      "meters": [
        { "name": "API requests", "code": "api_requests", "unit": "per 1,000 requests",
          "included": 2000, "quantity": 3412, "unit_rate": 0.4 },
        { "name": "Support hours", "code": "support_hours", "unit": "per hour",
          "included": 4, "quantity": 6 }
      ]
    }
  }' --output usage-report.pdf

Run against the API before publishing: 200, application/pdf — and that first meter comes back at 1,412 billable and $564.80, while the support hours are printed as measured and marked not priced, because no rate was sent for them.

The contract

Exactly what you send, exactly what you get.

These templates take named keys — no positional arguments, no layout to describe. Send a row array and the pagination follows it.

Usage report

238bb9b8-ef48-4c33-85cb-14a8b3bf8118

Fields · 28

provider_nameprovider_addressprovider_emailprovider_phoneprovider_tax_idreport_titlereport_numberissue_dateperiod_startperiod_endaccount_nameaccount_idaccount_emailenvironmentplan_nameplan_fee #plan_fee_labelminimum_commit #tax_labeltax_percent #currency_codecurrency_localeinvoice_referencepayment_termsnotesmethod_notecontact_namecontact_email

Rows · meters[]

name · code · unit · included · quantity · unit_rate

Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.

Rows · adjustments[]

label · description · amount

Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.

Rows · attribution[]

label · reference · meter · quantity

Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.

Renewal notice

d9b7cf93-4885-46d2-b501-d196ca117583

Fields · 24

brand_colorcompany_namecompany_urlbilling_emaileyebrowheadlineintrocustomer_nameaccount_nameaccount_idplan_nameseatsperiod_labelperiod_valuerenewal_datepayment_methodcurrency_codecurrency_localetax_labeltax_percent #manage_urlmanage_labelcancel_notefooter_note

Rows · lines[]

description · quantity · unit_price

Send as many as you have. Pagination, running totals and the carried-forward header are the renderer's problem, not yours.

What you would ask next.

Our billing system already computes the amounts. Why send counters?

Send them if you like — but not as a total. A row carrying its own charge, or a payload carrying its own subtotal or tax, is a 400 with the field named. One system decides the number and the arithmetic is printed beside it, so a customer who disagrees can point at a row instead of a figure.

We meter things we do not bill for yet.

Send them without a unit rate. The report prints the usage as measured, marks the row not priced, and states in a banner how many meters it left out of the total. It will not invent a price it was not given, and it will not quietly drop the meter either.

We have unlimited tiers and annual minimum commitments.

An allowance of -1 is unlimited: 9.4 million units at fifty cents bills nothing, and the row says unlimited rather than printing a number. A minimum commit appears as its own line, "Shortfall to minimum commit", never folded into a meter — and no line at all in a period that clears the floor.

Some accounts have sixty meters.

We tested sixty: four pages, the column header repeating on every page that carries rows, the running header carrying the account and the report number, and usage charges and total that still reconcile against an independent recomputation.

Can it look like our product rather than yours?

The workspace brand kit supplies the logo, the accent colour and the typeface, so the report leaves your product looking like your product. Templates are versioned: publish a new version when pricing changes and pin the old one to reproduce a historical period byte for byte.

Your system already knows when the document is owed.

Free to start · No credit card required