The statement payload
A statement.available body is one statement: an envelope of identifiers, the statement's own fields, and its meters, sections and charges. Charges hang off sections, and a section or charge may point at a meter.
Envelope
| Field | Type | Notes |
|---|---|---|
schema_version |
string | Contract version, for example 1.0.0 |
statement_id |
string | stt_…. Stable across re-extractions of the same bill |
version_id |
string | ver_…. One extraction of this statement |
is_latest |
boolean | True when sent: a version is current when it is delivered. A version you hold is superseded when a newer one arrives |
superseded_by |
string or null | Reserved. Null when sent; a later version does not update one you already hold |
parent_statement_id |
string | On a child of a summary bill only: the parent's statement_id |
request_id |
string | The request that delivered this version |
client_reference |
string | Echoed from your request, when you sent one |
document_id |
string | doc_…. The same for every statement from one file, and stable across re-extractions |
extracted_at |
string | UTC timestamp, ISO 8601. The number of fractional-second digits varies (none, 3, 6 or 9), so compare it as a time, never as a string. Statements from one extraction share it |
statement |
object | The statement's own fields, below |
meters, sections, charges |
arrays | Below |
children |
object | On a summary parent only. See Summary bills |
reconciliation |
object | The arithmetic, checked. See below |
confidence |
object | Checkable signals and a tier. See below |
issuer |
null | Reserved; currently always null |
connection_id and account_id are sent on statements retrieved through a connection (see Connecting a portal), and are absent on uploaded bills. provider appears in some samples but is not yet sent; it will be added in a minor version, so do not require it.
Values carry their printed form and their source
Money, quantities, dates and identifiers are objects, not bare values:
"amount_due": { "amount": 55.7, "as_printed": "55.70", "source": "extracted" }
"usage": { "value": 3, "unit": "thousand gallons", "as_printed": "3", "source": "extracted" }
"due_date": { "value": "2026-09-09", "as_printed": "9/9/2026", "source": "extracted" }
Amounts are numbers in the bill's currency, credits negative. Dates are YYYY-MM-DD. as_printed is the text on the bill, so you can always check a value against the document.
source |
Meaning |
|---|---|
extracted |
Read directly from the bill |
derived |
Calculated from other printed values, for example a period start from the end date and the day count |
inferred |
Not printed; concluded from context |
defaulted |
Not on the bill at all; a stated default, such as a total of 0.00 for a bill that prints no late fee |
statement
statement_date, due_date, period_start, period_end and account_number are value objects. totals holds amount_due, current_charges, previous_balance, balance_forward, late_fee, payments, credits and adjustments as money objects, each present when the bill prints or implies it. Also currency, service_address, is_summary, and location_id when the bill prints an identifier for the service location separate from the account number. statement_date and totals are always present.
Identifiers carry one more field. account_number, location_id and each meters[].number add normalized: the value's letters and digits only, in upper case. Luminetric computes it from value; the model never writes it. The same printed number always gives the same normalized, however the bill punctuates it, so 10-00001-00001 and 10 00001 00001 both give 100000100001. Leading zeros are kept.
"account_number": { "value": "10-00001-00001", "as_printed": "10-00001-00001", "source": "extracted", "normalized": "100000100001" }
Key accounts, locations and meters on normalized, and show value or as_printed to people. Where a provider issues one account for several locations, the account and location together identify a place: key on both normalized values. normalized is absent only when the identifier itself is.
meters, sections and charges
- meters[] —
meter_id(local to this statement),number(the meter number as printed),service,service_address,previous_readandcurrent_read,multiplier,read_startandread_enddates, andusageas a quantity object with its unit. - sections[] — each block of charges as the bill prints it:
section_id,heading_as_printed,service,service_source(how the service was decided),ordinal, optionalmeter_id, andprinted_totalwhen the bill prints a subtotal. - charges[] — each line:
name_as_printed,section_id,service,kind,amount,contributes_to_totalandservice_source, plusquantity,rate,meter_id,period_startandperiod_endwhen the bill gives them.
contributes_to_total is true for charges that make up current_charges. Payments, prior balances and printed subtotals are false, so summing the true rows reproduces the bill's current charges.
| Enum | Values |
|---|---|
service |
electric, gas, water, sewer, irrigation, stormwater, drainage, trash, fire, steam, chilled_water, internet, phone, tv, none, other, unknown |
kind |
supply, delivery, tax, fee, credit, adjustment, subtotal, other, unknown |
charges[].service_source |
section, item_text, meter, summary_row, single_service_bill, convention, inferred, none |
sections[].service_source |
heading, summary_row, item_text, meter, single_service_bill, inferred, none |
other means classified but not in the list. unknown means the bill gave nothing to classify it from, and is never a guess. none on service marks a line that belongs to no service, such as a payment or a bill-level late fee.
reconciliation
We check the arithmetic and report it. We never adjust a value to make it balance.
"reconciliation": {
"identity": "sum(charges where contributes_to_total) == statement.totals.current_charges",
"current_charges": 85.7, "sum_of_charges": 85.7, "delta": 0.0, "balanced": true,
"total_due": 55.7,
"total_due_identity": "previous_balance + payments + adjustments + current_charges",
"total_due_delta": 30.0, "total_due_balanced": false
}
balanced concerns the current charges and is the one to rely on. total_due_balanced is often false on a correct bill, because many bills print the balance forward differently, as in this example where a $30.00 credit is carried outside the printed identity.
confidence
"confidence": { "tier": "deliver", "reconciles": true, "key_totals_extracted": true,
"unknown_service_charge_count": 0, "signals_failed": [] }
Three signals, each one you can recompute from the payload: the charges reconcile, amount_due and current_charges were both read from the bill rather than derived, and no charge has an unknown service. tier is deliver when all three hold, and review when any fails, with the failures named in signals_failed.
review does not mean wrong. It means one of the checks could not confirm the statement, and it tells you which. A sensible policy is to load deliver statements automatically and route review statements to a person, or to automatic use only where the failed signal does not matter to you. Treat an unrecognized tier as review.