Published June 11, 2026
Hetzner invoice wrong? How to verify every line yourself
In this article
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:
| Source | Where to find it | What it gives you |
|---|---|---|
| Invoice PDF | Your account under "Invoices", or the link sent by email | The legal document: section subtotals, grouped product lines, VAT |
| Individual consumption statement | QR code on the invoice, the "see detailed usage" link in the PDF, or "Invoices" in your account; viewable in the browser, with CSV download | One row per resource: ID, name, start and end dates, rate, cap, metered usage |
| Usage preview | Hetzner Cloud Console | Current-month accrual per resource, before any invoice exists |
| Activity history | Account level in the Cloud Console, with a project filter and CSV export for a chosen date range | Create, 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.
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.
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:
- The invoice number and the exact PDF line items you dispute.
- The consumption CSV rows for those lines, with the
external idvalues highlighted. - The activity history evidence for each ID: creation and deletion timestamps, exported or captured as screenshots while still available.
- Your expected-charge calculation per row, in the same units the CSV uses.
- 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.
More from the blog
Hetzner's June 2026 price increase: how to scale around it
Hetzner's June 15 increase reprices new orders and rescales but leaves existing servers alone. How to lock in current rates and route growth around the hike.
Hetzner Cloud billing explained: hourly, monthly, and the invoice
Hetzner Cloud bills hourly with a monthly cap, rounds partial hours up, and invoices in arrears. Here's what actually shows up on your monthly invoice.