Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.termina.com/llms.txt

Use this file to discover all available pages before exploring further.

The bill upload endpoint accepts an energy bill PDF and returns structured billing data in a single request. Data will be validated on this endpoint in the pro plan. You send the file as multipart/form-data, and Termina extracts the retailer, account details, billing period, every charge line item with its tariff rates, and meter reads, then returns them as JSON alongside any validation issues that need review. It works for Australian, New Zealand, British and United States electricity, gas, and LPG bills across all major retailers.

Authentication

Every request must include your API key in the X-API-Key header. Requests without a valid key return 401 Unauthorized.

Example request

curl -X POST https://api.termina.io/api/v2/public/bills/upload/ \
  -H "X-API-Key: your-api-key-here" \
  -F "[email protected]"

Example response

{
  "bill_uuid": "9f3b2c1a-7d4e-4a2b-9c8f-1e6d5a4b3c2d",
  "energy_data": {
    "retailer_name": "Origin Energy",
    "account_number": "1234567890",
    "fuel_type": "elec",
    "site_identifier": "6203782197",
    "supply_address": "123 Example St, Melbourne VIC 3000",
    "billing_period": { "start_date": "2026-02-01", "end_date": "2026-02-28", "days": 28 },
    "invoice_number": "INV-4456120",
    "issue_date": "2026-03-03",
    "due_date": "2026-03-17",
    "charges": [
      {
        "classification": "Retail Peak",
        "tariff_name": "Peak usage",
        "amount": 412.50,
        "rate_steps": [
          { "rate": 27.5, "rate_unit": "cent/kWh", "quantity": 1500, "quantity_unit": "kWh", "amount": 412.50 }
        ]
      },
      {
        "classification": "Supply",
        "tariff_name": "Daily supply charge",
        "amount": 33.60,
        "rate_steps": [
          { "rate": 1.20, "rate_unit": "$/day", "quantity": 28, "quantity_unit": "days", "amount": 33.60 }
        ]
      }
    ],
    "total_amount": 490.71,
    "total_due": 490.71,
    "meter_reads": [
      {
        "meter_number": "M123456",
        "previous_read": 10500,
        "current_read": 12000,
        "consumption": 1500,
        "consumption_unit": "kWh",
        "read_type": "actual"
      }
    ]
  },
  "validation_issues": [
    {
      "severity": "WARNING",
      "field": "due_date",
      "message": "Due date inferred from issue date; not explicitly stated on the bill."
    }
  ]
}

What you get back

The response has three top-level fields:
  • bill_uuid: a unique identifier for the stored bill, used to reference it in later calls.
  • energy_data: the structured bill. This includes the retailer, account number, supply address, billing period, invoice and due dates, a full list of itemised charges (each classified and broken into tariff rate steps), totals, and meter reads. It is null if the bill could not be parsed.
  • validation_issues: a list of anything that needs attention, each with a severity (WARNING, ERROR, or ERROR_IGNORABLE), the affected field, and a message.

Common use cases

  • Procurement and bill validation: confirm a retailer has billed the correct rates against a contract.
  • Tariff comparison: extract current rates to benchmark against alternative offers.
  • Emissions and AASB S2 reporting: pull consumption and meter data as a structured input for Scope 2 reporting.
  • Portfolio management: ingest bills across multiple sites without manual data entry.
  • Embedded Products: Expose actions on your application when pricing or billing usage is required.

Frequently asked questions

The endpoint accepts energy bills as PDF, JPEG, PNG, or TIFF files sent as multipart/form-data under the file field. Both digital PDFs from retailer portals and scanned or photographed paper bills are supported.
Electricity, gas, and LPG bills. The extraction engine covers network charges, retail charges, environmental levies, market charges, and demand charges — with tariff rate steps and time-of-use breakdowns where present on the bill.
Over 30 fields including: retailer and account details, NMI/MIRN, supply address, billing period, invoice and due dates, every charge line item with its classification and tariff rate steps, time-of-use consumption breakdowns (peak, off-peak, shoulder), demand, meter readings, bill totals, and GST. See the full for every field and type.
Yes. Where time-of-use pricing is present on the bill, Termina extracts peak, off-peak, and shoulder rates and consumption separately — including the tariff rate steps and the kWh consumed in each period. See for the full field reference.
The energy_data field returns null and validation_issues describes what went wrong. Partial extractions return the data that was successfully read along with warnings on uncertain fields — so you always know what you can trust and what needs review.
Every extraction runs built-in validation that cross-checks the extracted charges against the bill total, verifies billing period dates are consistent, flags unusually high or low usage, and checks that tariff rates fall within expected ranges for the retailer and region. Issues are returned in the validation_issues array.
Include your API key in the X-API-Key request header. You can generate a free key instantly — no credit card required. See the for full authentication details and code examples.
Free tier accounts can process up to 50 bills total. Pro accounts have configurable rate limits based on your plan. The API returns a 429 status code with a Retry-After header if you exceed your limit. See for all status codes.