Docs: Overview

Overview

You send us a utility bill as a PDF, or give us a login to the utility's portal and we retrieve the bills ourselves. Either way, we send back one structured statement per bill, as signed JSON webhooks to an HTTPS endpoint you register. Every figure we send carries the text it was read from and says how it was obtained, so you can check any value against the bill.

This documentation describes contract version 1.0.0, frozen on October 14, 2026. Every endpoint and field it describes is live and is what the service produces today; the retrieval schedule starts when your account goes live. From 1.0.0 on, the rules in Compatibility and versioning apply.

How an integration works

An integration has two halves.

  1. You send a bill. One HTTPS request per PDF, authenticated with your API token. You choose the request_id, and you can attach your own client_reference, which we echo on everything we send back about that request.
  2. We answer every request at the webhook URL you registered. Most requests produce one statement. A summary bill produces a parent statement plus one child per metered service point, and a PDF holding several unrelated bills produces one statement for each. A request we cannot complete produces a request.failed event instead, and a file you already sent produces request.duplicate.

Or we retrieve the bills. Register a login to a utility portal once, choose which of its accounts you want, and we sign in on a schedule or whenever you ask. Each new bill is delivered exactly as an uploaded one would be, and every run ends in a retrieval.completed or retrieval.failed event. See Connecting a portal.

Processing is asynchronous. The upload returns as soon as the bill is queued. Results arrive by webhook. Turnaround is set in your service agreement, and a large summary bill takes longer than a single bill.

Request lifecycle: you post a bill, we answer 202, then send one of three events to your webhook; a later re-extraction may send a new version or a withdrawal. Your system Luminetric queues, extracts, checks Your webhook POST /v1/statements 202 Accepted statement.available or request.failed or request.duplicate later, if re-extracted a new version statement.withdrawn
One request, one of three answers: one or more statements, a failure, or a duplicate notice. Every arrow to your webhook is a signed POST. A portal connection also sends a retrieval.completed or retrieval.failed for each run.

A request ends in exactly one of three answers: statements, a failure or a duplicate notice. A later re-extraction can add a version or withdraw a statement.

Using an AI coding assistant

Point it at llms-full.txt. That one file holds a checklist of the details integration code most often gets wrong, this whole documentation, and the JSON Schema for every webhook body. Each page is also available as Markdown at the same address ending in .md, for example webhooks.md, and llms.txt indexes them all.

Terms

Term Meaning
Request One PDF you sent, identified by your request_id
Document That file. Its document_id is the same however many statements it yields
Statement One bill for one account and period (or one service point on a summary bill), identified by statement_id
Version One extraction of a statement, identified by version_id. A re-extraction delivers a new version under the same statement_id
Connection One login to one utility portal, identified by connection_id
Account One account a connection's login can see, identified by account_id. You choose which accounts we retrieve
Run One retrieval for a connection, scheduled or triggered by you, and retried under the same id when the portal could not be read. Identified by its own request_id
Event One webhook delivery, named in the Luminetric-Event header