---
name: energyaustralia-consumer-data-sharing
title: "Read EnergyAustralia customer accounts and billing under CDR consent"
description: >-
  Retrieve an EnergyAustralia customer's energy accounts, balances, invoices, billing
  transactions, concessions and payment schedule as an ACCC-accredited Consumer Data Right
  Data Recipient holding that customer's active consent. ACCREDITED-ONLY — this flow
  cannot be run without accreditation, certificates and consent.
api:
  - openapi/energyaustralia-data-holder-customers-api-openapi.yml
  - openapi/energyaustralia-energy-account-balances-api-openapi.yml
  - openapi/energyaustralia-energy-account-billing-api-openapi.yml
  - openapi/energyaustralia-energy-accounts-api-openapi.yml
base_url: https://authncdr.energyaustralia.com.au
auth: mTLS + OAuth2/OIDC (FAPI 1.0 Advanced)
gated: true
operations:
  - getCustomer
  - getCustomerDetail
  - listEnergyAccounts
  - getEnergyAccountDetail
  - getEnergyAccountBalance
  - listEnergyAccountBalancesBulk
  - listEnergyAccountBalancesSpecificAccounts
  - getEnergyAccountInvoices
  - listEnergyAccountInvoicesBulk
  - listEnergyInvoicesForSpecificAccounts
  - getBillingForEnergyAccount
  - listEnergyAccountBillingBulk
  - listEnergyAccountBillingForSpecificAccounts
  - getEnergyAccountPaymentSchedule
  - getEnergyAccountConcessions
generated: '2026-07-27'
method: generated
---

# Read EnergyAustralia customer accounts and billing under CDR consent

## Preconditions — read this before writing any code

There is **no developer signup**. Every step below is unreachable without:

1. ACCC accreditation as a Consumer Data Right Data Recipient — or operating as a CDR
   representative / sponsored ADR under an accredited intermediary.
2. Onboarding to the CDR Register, with client **transport and signing certificates**
   issued through the CDR Register PKI.
3. A registered software product.
4. **Per-consumer consent** obtained through the authorisation flow, with an explicit
   sharing duration.

EnergyAustralia's base URI is `https://authncdr.energyaustralia.com.au`, published in the
ACCC CDR Register (`dataHolderBrandId 1cc7833a-b834-ed11-a832-000d3a8830d6`, ABN
99086014968). Anonymous probes of every standards path on that host return HTTP 404 — that
is gating, not absence.

## Step 0 — authorisation

All calls go over **mutual TLS** with a CDR Register-issued client certificate. The access
token is obtained via an OAuth 2.0 authorization code flow under the FAPI 1.0 Advanced
profile: PKCE, Pushed Authorization Requests, signed request objects and `private_key_jwt`
client authentication, with the token bound holder-of-key to your certificate.

Resolve `authorization_endpoint` and `token_endpoint` from the data holder's OIDC discovery
document at `{publicBaseUri}/.well-known/openid-configuration`. **Do not hardcode them** —
that document is only readable over mTLS and its contents were not verifiable anonymously.

Request `openid` plus only the scopes you need. See `scopes/energyaustralia-scopes.yml`.

## Step 1 — confirm the customer (`getCustomer` / `getCustomerDetail`)

`GET /common/customer` at `x-v: 1` — scope `common:customer.basic:read`. Returns name and
occupation for a person, or agent name/role plus organisation name, industry code and
ABN/ACN for a non-individual.

`GET /common/customer/detail` at `x-v: 2` — scope `common:customer.detail:read`. Adds phone,
email, mail address and residential address.

Note the CDS given-name convention: where the holder cannot reliably split given names it
MAY return the whole string in `firstName` with an empty `middleNames` array. Do not assume
`firstName` is a single token.

## Step 2 — list the accounts (`listEnergyAccounts`)

`GET /energy/accounts` at `x-v: 2` — scope `energy:accounts.basic:read`.

Returns `data.accounts[]` with `accountId`, `accountNumber`, `displayName`, `creationDate`,
`plans` and `openStatus`. Paginate with `page` / `page-size` and read
`meta.totalRecords` / `meta.totalPages`.

`accountId` is the key for every step that follows.

## Step 3 — account detail (`getEnergyAccountDetail`)

`GET /energy/accounts/{accountId}` at `x-v: 4` — scope `energy:accounts.detail:read`.

Adds `plans[].servicePointIds` (the NMIs — your bridge to usage and DER data),
`plans[].planDetail` and `plans[].authorisedContacts`.

## Step 4 — the money

All four use scope `energy:billing:read`:

- **Balance** — `GET /energy/accounts/{accountId}/balance`
- **Invoices** — `GET /energy/accounts/{accountId}/invoices`. Each `EnergyInvoice` carries a
  `period` (mandatory when usage or demand charges are present), usage charges split by fuel,
  and an optional `payOnTimeDiscount`.
- **Billing transactions** — `GET /energy/accounts/{accountId}/billing` at `x-v: 3`.
  Discriminated by `transactionUType`: `usage`, `demand`, `onceOff`, `otherCharges`,
  `payment`. Switch on it; the sibling fields are conditional.
- **Payment schedule** — `GET /energy/accounts/{accountId}/payment-schedule`, scope
  `energy:accounts.paymentschedule:read`. Discriminated by `paymentScheduleUType`:
  `cardDebit`, `directDebit`, `digitalWallet`, `manualPayment`. Treat `bsb` and
  `accountNumber` on `directDebit` as sensitive; they are unmasked unless `isTokenised` is
  true.

Concessions: `GET /energy/accounts/{accountId}/concessions`, scope
`energy:accounts.concessions:read`.

## Step 5 — bulk vs specific-accounts

Every account-scoped resource has three shapes. Choose deliberately:

| Shape | Operation pattern | When |
|---|---|---|
| Single | `getEnergyAccountBalance` | One known account |
| Bulk | `listEnergyAccountBalancesBulk` (`GET /energy/accounts/balances`) | Every consented account |
| Specific | `listEnergyAccountBalancesSpecificAccounts` (`POST /energy/accounts/balances`) | A named subset |

The same triple exists for invoices (`getEnergyAccountInvoices` /
`listEnergyAccountInvoicesBulk` / `listEnergyInvoicesForSpecificAccounts`) and billing
(`getBillingForEnergyAccount` / `listEnergyAccountBillingBulk` /
`listEnergyAccountBillingForSpecificAccounts`).

**The POST variants are queries, not mutations.** POST is used only to carry a long
`data.accountIds[]` array in the request body. They are naturally idempotent; there is no
idempotency key in this API and none is needed. Prefer the specific-accounts POST over N
single calls — it is one round trip and one rate-limit charge.

## Error handling that matters here

The id-in-body POST operations return **HTTP 422**, not 404, for a bad id:

- `urn:au-cds:error:cds-energy:Authorisation/InvalidEnergyAccount` — permanent, do not retry.
- `urn:au-cds:error:cds-energy:Authorisation/UnavailableEnergyAccount` — transient, retry later.

The GET-with-id-in-path operations return the same two conditions as **HTTP 404**. Handle
both status codes for the same semantic condition.

Consent failures are 403: `Authorisation/RevokedConsent`, `Authorisation/InvalidConsent`,
`Authorisation/AdrStatusNotActive`. On `RevokedConsent`, stop and delete the data you hold —
do not retry. Full catalog in `errors/energyaustralia-problem-types.yml`.

## Conventions that apply to every call

- `x-v` required, per endpoint, values listed above. HTTP 406 on unsupported.
- `x-fapi-interaction-id` — send an RFC 4122 UUID, it is played back; log it.
- `x-fapi-auth-date` required for all resource calls.
- `x-fapi-customer-ip-address` and `x-cds-client-headers` for customer-present calls only.
- Errors are `application/json` with an `errors[]` array, **not** RFC 9457.
- HTTP 429 returns `Retry-After`; honour it.

See `conventions/energyaustralia-conventions.yml`.
