Back to all posts

Published June 11, 2026

Hetzner invoice wrong? How to verify every line yourself

Piotr HajkowskiBy Piotr Hajkowski

In this article

  1. The PDF alone cannot confirm a single charge
  2. A finished month has no cost data until its invoice arrives
  3. Match each PDF line to its consumption rows
  4. Recompute the expected charge from the row itself

In spring 2026, a Hetzner customer reported roughly €741 of charges, spread across four monthly invoices, for six floating IPs that had existed in the account for a few hours the previous December. On one invoice, a single IP appeared 18 times as identical €3.00 line items. First-line support reviewed the evidence and replied that "the calculation looks totally correct to us". The refund came months later, after the customer published the CSV evidence and the thread drew attention.

Most invoice doubts end less dramatically, but they start the same way: a line on the invoice you do not recognise, and a PDF that does not say which resource the charge belongs to. The previous article in this series, Hetzner Cloud billing explained, covered how the billing model works. This one answers the harder question: is this specific line correct? You can check that yourself, because every PDF line breaks down into per-resource rows in the individual consumption statement, every row carries a resource ID with start and end dates, and you can compare those dates with the activity history in the Cloud Console. The whole check takes about fifteen minutes per suspicious line.

The short version.

  • The Hetzner invoice PDF groups identical products into single lines, so it cannot confirm any individual charge.
  • Verification starts with the individual consumption statement: one row per resource, downloadable as CSV, with resource IDs, lifetimes, rates, and caps.
  • The statement only exists once its invoice does, which can be up to 28 days after the month ends.
  • Recompute each row from its quantity and unit price, then confirm the create and delete dates against the activity history in the Hetzner Cloud Console.
  • Billing errors can take any form, but check first for a duplicated resource ID in the same period, a charge after a documented deletion, and a total you cannot reproduce from the row's own numbers.

The PDF alone cannot confirm a single charge

Hetzner's billing system documentation states the design plainly: on the invoice PDF, "similar items are grouped together if the product, unit of measure, and unit price are identical", and "individual consumption values are not shown in the PDF invoice, but are provided in a separate individual consumption statement". The grouping hides a lot. On a real April invoice, position 15 of one Cloud project reads Product count 42, CX23 Cloud Server, 813 Hours, €5.2032: forty-two different servers, with their hours added into one quantity, on one line. That line could describe normal CI churn or one server billed forty-two times, and the PDF does not say which. It confirms the totals, but checking an individual charge needs the documents underneath it.

Four sources cover the whole chain:

SourceWhere to find itWhat it gives you
Invoice PDFYour account under "Invoices", or the link sent by emailThe legal document: section subtotals, grouped product lines, VAT
Individual consumption statementQR code on the invoice, the "see detailed usage" link in the PDF, or "Invoices" in your account; viewable in the browser, with CSV downloadOne row per resource: ID, name, start and end dates, rate, cap, metered usage
Usage previewHetzner Cloud ConsoleCurrent-month accrual per resource, before any invoice exists
Activity historyAccount level in the Cloud Console, with a project filter and CSV export for a chosen date rangeCreate, delete, attach, and assign events with timestamps and the user or API token that triggered them

The consumption statement is the document you will work with, and the activity history is how you confirm what it says.

A finished month has no cost data until its invoice arrives

The consumption statement is generated together with its invoice, and Hetzner's Cloud billing FAQ says how late that can be: "To space out invoices, we may create them up to 28 days after the last month was completed." The same FAQ rules out the obvious workaround: "It is not possible to view the usage data if you have not yet received your invoice for the previous month." The Usage preview does not fill the gap either, because on the first of the month it resets and shows only the new month's accrual.

Small accounts wait longer still. Hetzner generates an invoice only once the open amount exceeds €10; smaller balances accumulate, are combined across months into a single bill, and are invoiced at the latest after three consecutive months below the threshold. A €4 test project can run for a quarter before any document confirms what it cost.

1 Apr
1 Apr
1 May
1 May
28 May
28 May
April · Usage preview live
April · Usage preview live
Usage preview resets to May
Usage preview resets to May
no April cost document
invoice arrives any day here
no April cost documentinvoice arrives any day here
invoice + consumption statement
invoice + consumption statement
below €10: up to 3 more months
below €10: up to 3 more months
After a month ends, no Hetzner document covers it until the invoice arrives, up to 28 days later and longer when the balance stays below €10.

During that window the activity history is the only evidence that exists, which is one more reason to export it promptly instead of waiting for the invoice. The gap also delays every check: a January anomaly typically becomes visible in late February. This is partly why the ghost-IP case from the opening ran across four invoices.

Match each PDF line to its consumption rows

Start from the PDF line you doubt and find the matching rows in the consumption CSV. The CSV has one row per resource and billing condition, with these columns: grouping (the invoice section, such as a Cloud project or "Dedicated Server"), product, description (the resource name, and for IPs the address), reference (the parent resource a charge belongs to, such as the server an IPv4 add-on is attached to), quantity, from, until, condition (the rate, the cap, and the metered usage), unit, external id, price, and total.

Two rows from a real statement, abridged:

description      from        until       unit    external id       total
shared-nat-hel1  2026-04-04  2026-04-04  Hours   Server 125860314  €0.0064
shared-nat-hel1  2026-04-04  2026-04-30  Months  Server 125860544  €3.9900

condition: "€0.0064/h, max €3.99/mo. Usage: 1 h"    (first row)
condition: "€0.0064/h, max €3.99/mo. Usage: 627 h"  (second row)

The file opens in Excel and LibreOffice, with three catches. The condition field contains a line break, so rows look broken in a plain text editor but import correctly as long as the field stays quoted. The price and total cells hold text such as € 36.7000, which a spreadsheet will not sum until you strip the currency symbol into a helper column. And on a system set to German formats, Excel expects semicolons and a decimal comma, so use the import dialogue (Data → From Text/CSV), set the delimiter to comma, and read the numeric columns with the English number format.

The external id column is the one every later check uses. It holds the same resource ID the Cloud Console and the API use, so it still identifies the resource after deletion. Filter the CSV to the rows whose product, unit, and unit price match the PDF line, then check three sums: the row count must equal the Product count column on the PDF, the quantities must add up to the PDF quantity, and the row totals must add up to the PDF line total. For the 42-server line above, that means forty-two CSV rows whose hours sum to 813 and whose totals sum to €5.2032. When all three sums match, the PDF summarises the rows correctly, and the remaining question is whether the rows themselves are right.

Invoice PDF
Invoice PDF
one grouped line
one grouped line
Pos 15 · 42 × CX23 · 813 Hours · €5.2032
Pos 15 · 42 × CX23 · 813 Hours · €5.2032
sums must match
sums must match
Consumption CSV
Consumption CSV
one row per resource
one row per resource
Server 125860314 · 1 h
Server 125860314 · 1 h
Server 125860544 · 627 h
Server 125860544 · 627 h
… 40 more rows
… 40 more rows
42 rows · 813 h · €5.2032
42 rows · 813 h · €5.2032
external id
external id
Activity history
Activity history
create and delete events
create and delete events
created 2026-04-04
created 2026-04-04
deleted 2026-04-04
deleted 2026-04-04
One grouped PDF line breaks down into per-resource CSV rows, and each row's external ID links to the create and delete events in the activity history.

Recompute the expected charge from the row itself

Every row contains enough information to reproduce its own total. The unit column tells you which formula applies.

Hours rows cover resources that ran for part of the month: quantity is the rounded-up hour count, and the total is hours times the hourly rate.

AX41-NVMe: 109 hours × €0.0588/hour = €6.4092

Months rows mean the monthly cap was reached. The check is that the metered hours at the hourly rate would have met or exceeded the cap. This works in partial months too: the second shared-nat-hel1 row above was created on 4 April, yet bills as Months because 627 hours at €0.0064 computes to €4.01, which is above the €3.99 cap.

CX23: 627 hours × €0.0064/hour = €4.0128
€4.0128 is above the €3.99 cap, so billed €3.9900

GB-months rows cover volumes and snapshots. The condition field lists the inputs: quantity usage in GB, time usage in months, and the billable product of the two.

Snapshot: 0.8503 GB × 0.8903 months = 0.7570 GB-months
0.7570 GB-months × €0.0143/GB-month = €0.0108

TB rows are traffic overage. The condition shows used quota against included quota; the total must be the excess only, and €0.00 when usage stayed inside the allowance. Overage is billed in blocks of 0.0001 TB (the billing FAQ calls a block 100 MB).

Traffic: 0.6137 TB used - 0.5 TB included = 0.1137 TB over
0.1137 TB × €7.40/TB = €0.84

Traffic rows have a unit problem that the other row types do not. When Hetzner writes GB or TB, it means the binary units (GiB and TiB), everywhere: a plan documented as "0.5 TB" of included traffic comes back from the API as exactly 512 GiB, and the console, the Usage preview, and the consumption statement follow the same convention. A Hetzner "TB" is therefore 1,099,511,627,776 bytes, about 10% more than the plain trillion the label suggests. No Hetzner documentation states this; we established it by load-testing a server with a measured volume of egress and comparing every displayed figure with the API counter. The euro check above is unaffected, because it uses Hetzner's own displayed quantity. The units matter when you compare that quantity, or the included allowance, with your own traffic measurement: convert your bytes with the binary factor, because with the decimal factor the two figures disagree by about 9.5%, and a correct line fails the comparison. Even with matching units, expect a small remaining difference: in our test, the billed counter was about 3% higher than the server's own interface counter.

A row with wrong arithmetic is rare. Far more often the arithmetic is correct, and the real question is why the row exists at all. The activity history answers that.

Check the resource lifetime against the activity history

The from and until dates in the CSV state when the resource existed. The activity history in the Hetzner Cloud Console is where you confirm them. It sits at account level, at console.hetzner.com/activities, as one feed across all your projects; each project dashboard shows its recent entries too, but the link takes you out of the project into the account-level list. There you can filter by project and date range and export the result as CSV. Each event records the action taken, the timestamp, the resource concerned, the project, and the user or API token that triggered it. The Cloud API no longer offers a matching list: the endpoint that returned all actions in a project was removed on 30 January 2025, and actions now sit under each resource type, so for invoice checks the Console export is the practical route.

Two events from a real export, abridged:

activity_type  created            resources
server.create  2026-03-18 18:23Z  Server 124147042, stress-4cpu-16gb-hel1-1
server.delete  2026-03-26 05:30Z  Server 124147042, stress-4cpu-16gb-hel1-1

A consumption row for Server 124147042 must show from 2026-03-18, until 2026-03-26, and at most 180 rounded-up hours; a charge outside that window would be wrong. One reading note: the export lists most actions twice, once with status requested and once with success, so count each action once.

For each row you doubt, confirm three things. The creation event matches the from date. The deletion event, if any, matches the until date. And nothing was billed outside that window, which for a deleted resource means no row for the same external id appears in any later month's statement.

One caveat: Hetzner does not document a retention guarantee for action records. If an invoice looks wrong, export the relevant activity entries the day you notice, rather than assuming they will still be there when support replies. Better still, export the activity CSV on a regular schedule and keep your own archive, so the evidence for an older month is already saved when a question comes up.

Patterns that look like errors but are correct

Most suspicious lines turn out to be correct once you look at the resource ID. Four patterns account for nearly all of them. And if every line survives the checks while the total is still higher than you expected, the problem is usage rather than billing: Why your Hetzner bill is higher than expected covers that case.

The same server name appears on two rows

The two shared-nat-hel1 rows above look like a duplicate charge: same project, same product, same name, same day. The external IDs differ, because the server was deleted and recreated on 4 April. Server 125860314 lived for under an hour; Server 125860544 is its replacement and ran out the month. A name can be reused, but each ID is a separate resource, and billing follows the ID.

The same IP address appears on three rows

A consumption statement can show one IPv4 address three times, under three different Primary IP external IDs, in one month. That happens when an address is released and re-acquired: each acquisition is a new resource with its own row and its own rounded-up first hour. Three rows for one address under three different IDs is normal churn. Three rows with the same ID would be a genuine problem, and the next section covers it.

Dozens of one-hour lines at the bottom of a project

CI pipelines, Packer image builds, and cluster auto-provisioning leave dozens of rows like packer-69f30a28..., 1 hour, €0.0064. Each is a short-lived server that existed for minutes and was billed for its rounded-up hour, exactly as the round-up rule says. Individually they cost less than a cent, and together they show your automation's churn rather than a billing fault. These are also the rows behind the high Product count values on the PDF, such as the 42-server line above.

A charge for a resource deleted weeks ago

Hetzner invoices in arrears, so the invoice that arrives in June settles May. A resource deleted in late May appears on that invoice correctly, exactly once. An error would be the same resource appearing again the month after.

What a genuine Hetzner invoice error looks like

The €741 case from the opening shows where a real error can hide. The arithmetic on each line was internally consistent, which is presumably why first-line support saw a calculation that "looks totally correct". The defect was in the rows themselves: the same floating IPs, under the same identifiers, repeated 4 to 18 times within a single billing period, for resources whose deletion months earlier was documented. No legitimate pattern produces that.

No list of billing errors is complete; a new defect can look like anything, and the checks in this article can then only tell you that something does not add up. The cases reported so far show four warning signs:

  • The same external ID appears more than once for the same product and overlapping period. Recreated resources get new IDs; a repeated ID within one period is double billing.
  • A charge in a month after the documented deletion. One final invoice after deletion is the arrears rule at work, but a row for the same ID two months on means the billing system has lost track of the resource.
  • Metered usage exceeds the hours in the month. No resource can use 800 hours in April.
  • The CSV rows do not sum to the PDF line. This points at the grouping itself rather than any single resource.

Build the evidence pack before you open the ticket

Billing questions go through a support request from your customer account; Hetzner's payment documentation names that as the fastest route, with [email protected] as the fallback when you cannot sign in. What you attach decides whether support can resolve the ticket on first contact. At a minimum, include:

  1. The invoice number and the exact PDF line items you dispute.
  2. The consumption CSV rows for those lines, with the external id values highlighted.
  3. The activity history evidence for each ID: creation and deletion timestamps, exported or captured as screenshots while still available.
  4. Your expected-charge calculation per row, in the same units the CSV uses.
  5. The delta: billed total minus expected total, per invoice.

A claim phrased as "Primary IP 125084797 was deleted on 2026-04-04 per the project activity log, yet appears with the same ID on the May and June statements; expected €0.0008, billed €1.0008" gives a billing specialist something to verify rather than something to interpret. The €741 case was eventually refunded on exactly this kind of evidence; the months of delay came from the claim being escalated step by step, and clear evidence speeds that up.

Every euro should be explainable

An unexplained line is rarely a one-off. The ghost IPs in the opening case ran across four invoices because nothing on Hetzner's side would have stopped the repeat charges, and each unchallenged month added roughly €185 to the total. Whatever is unexplained on this month's invoice will be on next month's too.

So practise the check while nothing is wrong. On your next two or three invoices, match one PDF line to its CSV rows, recompute a total, and look up an external ID in the activity history. The first pass is slow, but by the third you need only minutes. With luck you will never need it for a real dispute, but if a line ever looks wrong, you can run the whole check the day you notice it instead of learning the process while the charges repeat.

The month-to-month watching is still worth automating. CloudTally records each resource's lifecycle as it happens and keeps a running expected charge beside it, so whenever Hetzner's invoice arrives, it only confirms what you already know.