openapi: "3.1.0"
info:
  title: openfeed - Sharing API
  version: "1.0.0"
  description: |
    openfeed Sharing API

    **Major features:**
    - **Banking & energy data** — accounts, account detail (rates, fees,
      features, bundles, plan tariffs), transactions, meters, usage,
      DER configuration, billing transactions, and invoices.
    - **Grant management** — apps can list, query, and revoke their own
      grants.
    - **App self-service** — apps can look up their own registration
      details.

    Data and Grant Management endpoints require a grant-bound bearer token with active consent;
    App endpoints require an app token with appropriate scopes;

    **Pagination:** collection endpoints use offset pagination via the
    `limit` (default and max 1000) and `offset` (default 0) query
    parameters. Responses carry `meta.{limit,offset}` (the effective values
    applied) and a `links` object with `self` (the current page) and `next`
    (the next page — present only when a further record exists).


servers:
  - url: https://api.openfeed.au
    description: openfeed

security:
  - oauth2: []
# All endpoints require an OAuth 2.0 bearer token. Endpoints that require
# specific scopes declare them explicitly.

components:
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: /oauth/authorize
          tokenUrl: /oauth/token
          scopes:
            openfeed-au:data:banking:read: Read banking accounts and transactions
            openfeed-au:data:energy:read: Read energy accounts and usage data
            openfeed-au:grant:self:query: Query grants belonging to the calling app
            openfeed-au:grant:self:revoke: Revoke grants belonging to the calling app
        clientCredentials:
          tokenUrl: /oauth/token
          scopes:
            openfeed-au:app:all:read: Read the calling app's registration details (GET /v1/app). Obtained via client_credentials — no grant_id required.
            openfeed-au:grant:all:list: List all grants for the calling app (GET /v1/app/grants). Obtained via client_credentials — no grant_id required.

  schemas:
    ProviderRef:
      type: object
      description: Identifies the source provider (institution) for an account.
      required: [providerId, providerName]
      properties:
        providerId:
          type: string
          description: Unique identifier for the provider/institution.
        providerName:
          type: string
          description: Display name of the provider.

    ErrorResponse:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
          description: Machine-readable error code.
        message:
          type: string
          description: Human-readable explanation.

    BankingRateCondition:
      type: object
      description: |
        A condition attached to a rate or rate tier that constrains when the
        rate applies (e.g. new customers only, minimum deposit amount).
        Mirrors the Australian Consumer Data Standards
        `BankingProductRateCondition` schema.
      properties:
        rateApplicabilityType:
          type: string
          description: Category of applicability condition.
          enum:
            - MIN_DEPOSITS
            - MIN_DEPOSIT_AMOUNT
            - DEPOSIT_BALANCE_INCREASED
            - EXISTING_CUST
            - NEW_ACCOUNTS
            - NEW_CUSTOMER
            - NEW_CUSTOMER_TO_GROUP
            - ONLINE_ONLY
            - OTHER
            - MIN_PURCHASES
            - MAX_WITHDRAWALS
            - MAX_WITHDRAWAL_AMOUNT
        additionalValue:
          type: string
          description: |
            Additional information relevant to the `rateApplicabilityType`
            (interpretation depends on that type).
        additionalInfo:
          type: string
          description: |
            Free-text display information about the condition. Mandatory when
            `rateApplicabilityType` is `OTHER`.
        additionalInfoUri:
          type: string
          format: uri
          description: Link to a web page with more information on this condition.

    BankingRateTier:
      type: object
      description: |
        A balance/term band that determines when a rate applies (e.g.
        "Balance $0–$5,000 @ 0.10%"). Mirrors the Australian Consumer Data
        Standards `BankingProductRateTier` schema.
      properties:
        name:
          type: string
          description: Display name for the tier (e.g. "Balance $0 – $5,000").
        unitOfMeasure:
          type: string
          description: |
            Unit that `minimumValue` and `maximumValue` are counted in.
            - `DOLLAR` — a dollar amount
            - `PERCENT` — a rate (e.g. Loan-to-Value Ratio)
            - `MONTH` / `DAY` — a period (fixed-term deposit or loan)
          enum: [DAY, DOLLAR, MONTH, PERCENT]
        minimumValue:
          type: string
          description: Lower bound of the tier, inclusive, in `unitOfMeasure` units.
        maximumValue:
          type: string
          description: |
            Upper bound of the tier, in `unitOfMeasure` units. For a discrete
            value (e.g. 1 month), this equals `minimumValue`. Where this
            equals the `minimumValue` of the next-higher tier, this tier is
            exclusive of that value. Absent = no upper bound.
        rateApplicationMethod:
          type: string
          description: |
            How the rate is applied across tiers.
            - `WHOLE_BALANCE` — the tier's rate applies to the entire balance
            - `PER_TIER` — each tier's rate applies only to the portion of
              the balance that falls into that tier (band/step method)
          enum: [PER_TIER, WHOLE_BALANCE]
        applicabilityConditions:
          type: array
          description: Additional conditions gating this tier.
          items:
            $ref: "#/components/schemas/BankingRateCondition"
        additionalInfo:
          type: string
          description: Free-text display information about the tier.
        additionalInfoUri:
          type: string
          format: uri
          description: Link to a web page with more information on this tier.

    BankingDepositRate:
      type: object
      description: Deposit rate tier for a savings/deposit product. No PII.
      properties:
        rate:
          type: string
          description: The interest rate as a percentage (e.g. "0.25").
        rateType:
          type: string
          description: Rate type (e.g. FIXED, VARIABLE, FLOATING).
        calculationFrequency:
          type: string
          description: Calculation frequency (e.g. DAILY, MONTHLY, ANNUAL).
        tiers:
          type: array
          description: |
            Balance/term tiers that determine when this rate applies (e.g.
            different rates for different balance bands).
          items:
            $ref: "#/components/schemas/BankingRateTier"
        applicationFrequency:
          type: string
          description: Application frequency (e.g. DAILY, MONTHLY, ANNUAL).
        additionalInfo:
          type: string
          description: Additional information (free text).

    BankingLendingRate:
      type: object
      description: Lending rate tier for a loan/credit product. No PII.
      properties:
        rate:
          type: string
          description: The interest rate as a percentage (e.g. "4.50").
        rateType:
          type: string
          description: Rate type (e.g. FIXED, VARIABLE).
        calculationFrequency:
          type: string
          description: Calculation frequency (e.g. DAILY, MONTHLY, ANNUAL).
        tiers:
          type: array
          description: |
            Balance/term tiers that determine when this rate applies (e.g.
            first $250,000 at one rate, remainder at another).
          items:
            $ref: "#/components/schemas/BankingRateTier"
        applicationFrequency:
          type: string
          description: Application frequency.
        additionalInfo:
          type: string
          description: Additional information.

    BankingFeeDiscountAmount:
      type: object
      description: |
        Fixed-dollar-amount variant of a fee discount. Populated when the
        parent discount's `discountMethodUType` is `fixedAmount`. Mirrors the
        Australian Consumer Data Standards `BankingFeeDiscountAmount` schema.
      properties:
        amount:
          type: string
          description: |
            The specific dollar amount discounted from the fee each time it
            is incurred (AmountString).

    BankingFeeDiscountRange:
      type: object
      description: |
        Minimum/maximum cap for a rate-based fee discount when the exact
        amount is not known until the fee is incurred. Mirrors the
        Australian Consumer Data Standards `BankingFeeDiscountRange` schema.
      properties:
        discountMinimum:
          type: string
          description: Minimum fee discount applied per occurrence (AmountString).
        discountMaximum:
          type: string
          description: Maximum fee discount applied per occurrence (AmountString).

    BankingFeeDiscountRate:
      type: object
      description: |
        Rate-based variant of a fee discount. Populated when the parent
        discount's `discountMethodUType` is `rateBased`. Unless noted in
        `additionalInfo`, assumes the application and calculation frequency
        match the parent fee. Mirrors the Australian Consumer Data Standards
        `BankingFeeDiscountRate` schema.
      properties:
        rateType:
          type: string
          description: |
            What the rate is calculated against.
            - `BALANCE` — discount based on the account balance
            - `FEE` — discount based on the parent fee amount
            - `INTEREST_ACCRUED` — discount based on interest accrued
            - `TRANSACTION` — discount based on a transaction
          enum: [BALANCE, FEE, INTEREST_ACCRUED, TRANSACTION]
        rate:
          type: string
          description: The rate applied to the `rateType` value (RateString).
        amountRange:
          $ref: "#/components/schemas/BankingFeeDiscountRange"

    BankingDiscountEligibility:
      type: object
      description: |
        Eligibility constraint that must be satisfied to receive a fee
        discount. Mirrors the Australian Consumer Data Standards
        `BankingProductDiscountEligibility` schema. The `STAFF` value in
        `discountEligibilityType` refers to a staff member of the provider
        (data holder), per CDS terminology.
      properties:
        discountEligibilityType:
          type: string
          description: |
            The eligibility category. Some values require an `additionalValue`:
            - `MIN_AGE` / `MAX_AGE` — value is the age in years
            - `MIN_INCOME` / `MIN_TURNOVER` — value is an AmountString
            - `INTRODUCTORY` — value is an ISO 8601 Duration
            - `OTHER` — `additionalInfo` becomes mandatory
          enum:
            - BUSINESS
            - EMPLOYMENT_STATUS
            - INTRODUCTORY
            - MAX_AGE
            - MIN_AGE
            - MIN_INCOME
            - MIN_TURNOVER
            - NATURAL_PERSON
            - OTHER
            - PENSION_RECIPIENT
            - RESIDENCY_STATUS
            - STAFF
            - STUDENT
        additionalValue:
          type: string
          description: Value whose interpretation depends on `discountEligibilityType`.
        additionalInfo:
          type: string
          description: |
            Display text explaining the constraint. Mandatory when
            `discountEligibilityType` is `OTHER`.
        additionalInfoUri:
          type: string
          format: uri
          description: Link to a web page with more information on this constraint.

    BankingFeeDiscount:
      type: object
      description: |
        A discount that reduces or waives a fee under specified conditions
        (e.g. waived for pensioners, 50% off during an introductory period,
        or a fee cap). Mirrors the Australian Consumer Data Standards
        `BankingProductDiscount` schema. The currency of a discount matches
        the currency of its parent fee.
      properties:
        description:
          type: string
          description: Human-readable description of the discount.
        discountType:
          type: string
          description: |
            Category of discount.
            - `BALANCE` — discount applies when a balance threshold is met
            - `DEPOSITS` — discount applies based on deposit activity
            - `ELIGIBILITY_ONLY` — discount applies purely by eligibility
              (see `eligibility[]`)
            - `FEE_CAP` — discount caps the fee at a maximum amount
            - `PAYMENTS` — discount applies based on payment activity
          enum: [BALANCE, DEPOSITS, ELIGIBILITY_ONLY, FEE_CAP, PAYMENTS]
        discountMethodUType:
          type: string
          description: |
            Discriminator for the discount method. Selects which sibling
            property (`fixedAmount` or `rateBased`) holds the discount value.
          enum: [fixedAmount, rateBased]
        fixedAmount:
          allOf:
            - $ref: "#/components/schemas/BankingFeeDiscountAmount"
          description: Present when `discountMethodUType` is `fixedAmount`.
        rateBased:
          allOf:
            - $ref: "#/components/schemas/BankingFeeDiscountRate"
          description: Present when `discountMethodUType` is `rateBased`.
        additionalValue:
          type: string
          description: |
            Additional value whose interpretation depends on `discountType`.
        additionalInfo:
          type: string
          description: Free-text display information about the discount.
        additionalInfoUri:
          type: string
          format: uri
          description: Link to a web page with more information on this discount.
        eligibility:
          type: array
          description: |
            Eligibility constraints. Mandatory when `discountType` is
            `ELIGIBILITY_ONLY`.
          items:
            $ref: "#/components/schemas/BankingDiscountEligibility"

    BankingFee:
      type: object
      description: Account fee or charge. No PII.
      properties:
        name:
          type: string
          description: Fee name (e.g. "Monthly Account Fee").
        feeType:
          type: string
          description: Fee type (e.g. PERIODIC, TRANSACTION, ESTABLISHMENT).
        amount:
          type: string
          description: Fixed fee amount (if applicable).
        balanceRate:
          type: string
          description: Fee as a % of balance (if applicable).
        transactionRate:
          type: string
          description: Fee as a % of transaction value (if applicable).
        accruedRate:
          type: string
          description: Fee accrual rate.
        discounts:
          type: array
          description: |
            Discounts (including waivers and caps) that apply to this fee.
          items:
            $ref: "#/components/schemas/BankingFeeDiscount"
        additionalInfo:
          type: string
          description: Additional fee information.

    BankingFeature:
      type: object
      description: Product feature or benefit. No PII.
      properties:
        featureType:
          type: string
          description: Feature type (e.g. CARD_ACCESS, OFFSET, PAY_TO_SOMEONE).
        additionalValue:
          type: string
          description: Additional feature information.
        additionalInfo:
          type: string
          description: Detailed description.
        additionalInfoUri:
          type: string
          description: URI to additional information.

    BankingProductBundle:
      type: object
      description: |
        A package of two or more products offered together (e.g. transaction
        account + savings + credit card with waived monthly fees). Mirrors
        the Australian Consumer Data Standards `BankingProductBundle` schema.
      properties:
        name:
          type: string
          description: Name of the bundle.
        description:
          type: string
          description: Description of the bundle.
        additionalInfo:
          type: string
          description: Free-text display information about the bundle.
        additionalInfoUri:
          type: string
          format: uri
          description: Link to a web page with more information on the bundle.
        productIds:
          type: array
          description: |
            IDs of products included in the bundle that are available via the
            provider's product endpoints. Not necessarily an exhaustive list
            — some bundled products may not be exposed as separate reference
            products.
          items:
            type: string

    BankingAccount:
      allOf:
        - $ref: "#/components/schemas/ProviderRef"
        - type: object
          required: [accountId, displayName]
          properties:
            accountId:
              type: string
              description: Stable, provider-scoped account identifier. Opaque to the client; safe to index/cache by.
            displayName:
              type: string
              description: Human-readable account name (e.g. "Everyday Account").
            accountType:
              type: string
              description: |
                Category of banking product. Values reflect the Australian
                Consumer Data Standards banking product categories:
                `TRANS_AND_SAVINGS_ACCOUNTS`, `TERM_DEPOSITS`,
                `TRAVEL_CARDS`, `REGULATED_TRUST_ACCOUNTS`,
                `RESIDENTIAL_MORTGAGES`, `CRED_AND_CHRG_CARDS`,
                `PERS_LOANS`, `MARGIN_LOANS`, `LEASES`, `TRADE_FINANCE`,
                `OVERDRAFTS`, `BUSINESS_LOANS`.
            productCategory:
              type: string
              description: |
                Sub-category of banking product. Same value space as
                `accountType`; retained for consumers that key off product
                category rather than account type.
            status:
              type: string
              description: |
                Account status. One of: `OPEN` (active and usable),
                `CLOSED` (closed), `SUSPENDED` (temporarily unavailable).
            maskedNumber:
              type: string
              description: Masked account number as supplied by the provider (already masked; not PII).
            productName:
              type: string
              description: Provider product name for the account.
            accountOwnership:
              type: string
              description: Account ownership (e.g. UNKNOWN, ONE_PARTY, TWO_PARTY, MANY_PARTY, OTHER).
            creationDate:
              type: string
              description: Account creation date as supplied by the provider (ISO date string).
            isOwned:
              type: boolean
              description: Whether the consumer is an owner of the account.

    BankingAccountDetail:
      allOf:
        - $ref: "#/components/schemas/BankingAccount"
        - type: object
          properties:
            payloadVersion:
              type: integer
              default: 1
              description: |
                openfeed payload version. Currently always 1; reserved for
                future backwards-compatible additions.
            depositRates:
              type: array
              description: Deposit/savings rates for this account (if applicable). No PII.
              items:
                $ref: "#/components/schemas/BankingDepositRate"
            lendingRates:
              type: array
              description: Lending rates for this account (if applicable). No PII.
              items:
                $ref: "#/components/schemas/BankingLendingRate"
            fees:
              type: array
              description: Account fees and charges. No PII.
              items:
                $ref: "#/components/schemas/BankingFee"
            features:
              type: array
              description: Product features and benefits. No PII.
              items:
                $ref: "#/components/schemas/BankingFeature"
            bundles:
              type: array
              description: Product bundles or package groupings that include this account. No PII.
              items:
                $ref: "#/components/schemas/BankingProductBundle"

    BankingTransaction:
      type: object
      description: |
        A banking transaction line item. Content follows the Australian
        Consumer Data Standards banking transaction schema. Free-text fields
        (`description`, `reference`, `merchantName`) are PAN-scrubbed at
        ingestion; residual PII risk is documented in the openfeed privacy
        model.
      required: [transactionId, accountId]
      properties:
        transactionId:
          type: string
          description: Stable, opaque transaction identifier.
        accountId:
          type: string
          description: Identifier of the account this transaction belongs to.
        amount:
          type: string
          description: |
            Transaction amount in the account's currency. Positive for
            credits, negative for debits (AmountString, ISO 20022 format).
        currency:
          type: string
          description: Currency of the transaction amount (ISO 4217, e.g. `AUD`).
        transactionDate:
          type: string
          format: date
          description: Date the transaction occurred, as recorded by the provider.
        valueDate:
          type: string
          format: date
          description: Date the transaction affected the balance for interest / cleared-funds purposes.
        postedDateTime:
          type: string
          format: date-time
          description: Date and time the transaction was posted to the account.
        description:
          type: string
          description: |
            Free-text description of the transaction, as provided by the
            data source. PAN-scrubbed at ingestion.
        transactionType:
          type: string
          description: |
            Category of transaction. Values reflect the Australian Consumer
            Data Standards banking transaction types: `FEE`,
            `INTEREST_CHARGED`, `INTEREST_PAID`, `TRANSFER_OUTGOING`,
            `TRANSFER_INCOMING`, `PAYMENT`, `DIRECT_DEBIT`, `OTHER`.
        status:
          type: string
          description: |
            Whether the transaction is fully settled or still pending. One
            of: `PENDING`, `POSTED`.
        merchantCategoryCode:
          type: string
          description: ISO 18245 merchant category code. Not PII.
        billerCode:
          type: string
          description: BPAY biller code. Not PII.
        billerName:
          type: string
          description: BPAY biller name. Not PII.
        executionDateTime:
          type: string
          description: Transaction execution date-time as supplied by the provider (ISO date-time string).
        apcaNumber:
          type: string
          description: APCA identifier of the originating/receiving institution. Not PII.
        reference:
          type: string
          description: >-
            Free-text reference from the originating institution. PAN-scrubbed at
            ingestion (same residual-risk class as description).
        merchantName:
          type: string
          description: >-
            Merchant business name (free text). PAN-scrubbed at ingestion.

    EnergyPlanOverview:
      type: object
      description: High-level plan overview details. No PII.
      properties:
        displayName:
          type: string
          description: Plan display name.
        startDate:
          type: string
          format: date
          description: Plan start date (ISO date).
        endDate:
          type: string
          format: date
          description: Plan end date (ISO date), if applicable.

    EnergyPlanRate:
      type: object
      description: |
        A unit price and (optional) volume band. Mirrors the Australian
        Consumer Data Standards `EnergyPlanRate` schema.
      properties:
        unitPrice:
          type: string
          description: Unit price of usage per measure unit, exclusive of GST (AmountString).
        measureUnit:
          type: string
          description: |
            The measurement unit for `unitPrice`. Assumed `KWH` when absent.
          enum: [KWH, KVA, KVAR, KVARH, KW, DAYS, METER, MONTH]
        volume:
          type: number
          description: |
            Volume that this rate applies to. Only populated for stepped
            rates (different rates for different usage volumes in a period).

    EnergyTariffPeriodSingleRate:
      type: object
      description: |
        A single flat rate for a tariff period, applicable when the parent
        tariff period's `rateBlockUType` is `singleRate`. Mirrors the
        Australian Consumer Data Standards `EnergyPlanTariffPeriodSingleRate`
        schema.
      properties:
        displayName:
          type: string
          description: Display name of the rate.
        description:
          type: string
          description: Description of the rate.
        generalUnitPrice:
          type: string
          description: |
            Block rate (unit price) for any usage above the included fixed
            usage, in dollars per kWh inclusive of GST. Only present when
            the parent plan's pricing model is `QUOTA` (AmountString).
        rates:
          type: array
          description: Rates in order of usage volume (for stepped/block pricing).
          items:
            $ref: "#/components/schemas/EnergyPlanRate"
        period:
          type: string
          description: |
            Usage period for which the block rate applies. Formatted as an
            ISO 8601 Duration (excludes recurrence syntax), e.g. `PT2H30M`.

    EnergyTariffPeriodTimeOfUseWindow:
      type: object
      description: |
        A time-of-day/day-of-week window during which a time-of-use rate
        applies. Mirrors the CDS `EnergyPlanTariffPeriodTimeOfUseRate.timeOfUse`
        inner schema.
      properties:
        days:
          type: array
          description: Days on which the rate applies.
          items:
            type: string
            enum: [SUN, MON, TUE, WED, THU, FRI, SAT, PUBLIC_HOLIDAYS]
        startTime:
          type: string
          description: |
            Start of the period as an ISO 8601 time (e.g. `17:00:00.000+10:00`).
            If a UTC offset is omitted, the parent plan's timezone applies.
        endTime:
          type: string
          description: |
            End of the period as an ISO 8601 time. Same offset rules as
            `startTime`.

    EnergyTariffPeriodTimeOfUseRate:
      type: object
      description: |
        A time-of-use rate for a tariff period, applicable when the parent
        tariff period's `rateBlockUType` is `timeOfUseRates`. Mirrors the
        Australian Consumer Data Standards
        `EnergyPlanTariffPeriodTimeOfUseRate` schema.
      properties:
        displayName:
          type: string
          description: Display name of the rate.
        description:
          type: string
          description: Description of the rate.
        rates:
          type: array
          description: Rates in order of usage volume (for stepped/block pricing).
          items:
            $ref: "#/components/schemas/EnergyPlanRate"
        timeOfUse:
          type: array
          description: Time windows during which this rate applies.
          items:
            $ref: "#/components/schemas/EnergyTariffPeriodTimeOfUseWindow"
        type:
          type: string
          description: The type of usage that the rate applies to.
          enum: [PEAK, OFF_PEAK, SHOULDER, SHOULDER1, SHOULDER2]

    EnergyPlanTariffDemandCharge:
      type: object
      description: |
        A demand-based tariff charge (billed on peak instantaneous demand,
        not accumulated usage). Applicable when the parent tariff period's
        `rateBlockUType` is `demandCharges`. Mirrors the Australian Consumer
        Data Standards `EnergyPlanTariffDemandCharge` schema.
      properties:
        displayName:
          type: string
          description: Display name of the charge.
        description:
          type: string
          description: Description of the charge.
        amount:
          type: string
          description: Charge amount per measure unit, exclusive of GST (AmountString).
        measureUnit:
          type: string
          description: Measurement unit for `amount`. Assumed `KVA` when absent.
          enum: [KWH, KVA, KVAR, KVARH, KW, DAYS, METER, MONTH]
        startTime:
          type: string
          description: Start of the demand period (ISO 8601 time).
        endTime:
          type: string
          description: End of the demand period (ISO 8601 time).
        days:
          type: array
          description: Days on which the demand tariff applies.
          items:
            type: string
            enum: [SUN, MON, TUE, WED, THU, FRI, SAT, PUBLIC_HOLIDAYS]
        minDemand:
          type: string
          description: Minimum demand for this tariff in kW. Defaults to `0.00` (AmountString).
        maxDemand:
          type: string
          description: Maximum demand for this tariff in kW, when present (AmountString).
        measurementPeriod:
          type: string
          description: Application period for the demand tariff.
          enum: [DAY, MONTH, TARIFF_PERIOD]
        chargePeriod:
          type: string
          description: Charge period for the demand tariff.
          enum: [DAY, MONTH, TARIFF_PERIOD]

    EnergyTariffPeriod:
      type: object
      description: |
        A pricing period within a plan, with the rate structure that applies
        during it. Mirrors the Australian Consumer Data Standards
        `EnergyPlanTariffPeriod` schema. One of `singleRate`,
        `timeOfUseRates`, or `demandCharges` is populated per the
        `rateBlockUType` discriminator.
      properties:
        type:
          type: string
          description: Type of charge. Assumed `OTHER` when absent.
          enum: [ENVIRONMENTAL, REGULATED, NETWORK, METERING, RETAIL_SERVICE, RCTI, OTHER]
        displayName:
          type: string
          description: Display name of the tariff period.
        startDate:
          type: string
          pattern: ^\d\d-\d\d$
          description: |
            Start of the tariff period in a calendar year, formatted `MM-DD`
            (not a full date — this is a recurring annual date).
        endDate:
          type: string
          pattern: ^\d\d-\d\d$
          description: End of the tariff period, formatted `MM-DD`.
        dailySupplyCharges:
          type: string
          description: Daily access charge for the tariff period, in dollars per day exclusive of GST (AmountString).
        timeZone:
          type: string
          description: |
            Timezone used to calculate time-of-use thresholds. If absent,
            the parent plan contract's timezone applies.
          enum: [LOCAL, AEST]
        rateBlockUType:
          type: string
          description: |
            Discriminator selecting which of the sibling rate structures is
            populated for this period.
          enum: [singleRate, timeOfUseRates, demandCharges]
        singleRate:
          allOf:
            - $ref: "#/components/schemas/EnergyTariffPeriodSingleRate"
          description: Present when `rateBlockUType` is `singleRate`.
        timeOfUseRates:
          type: array
          description: Present when `rateBlockUType` is `timeOfUseRates`.
          items:
            $ref: "#/components/schemas/EnergyTariffPeriodTimeOfUseRate"
        demandCharges:
          type: array
          description: Present when `rateBlockUType` is `demandCharges`.
          items:
            $ref: "#/components/schemas/EnergyPlanTariffDemandCharge"

    EnergyPlanFee:
      type: object
      description: |
        A fee associated with a plan (e.g. exit fee, late-payment fee).
        Mirrors the Australian Consumer Data Standards `EnergyPlanFee` schema.
      properties:
        type:
          type: string
          description: Category of fee.
          enum:
            - EXIT
            - ESTABLISHMENT
            - LATE_PAYMENT
            - DISCONNECTION
            - DISCONNECT_MOVE_OUT
            - DISCONNECT_NON_PAY
            - RECONNECTION
            - CONNECTION
            - PAYMENT_PROCESSING
            - CC_PROCESSING
            - CHEQUE_DISHONOUR
            - DD_DISHONOUR
            - MEMBERSHIP
            - CONTRIBUTION
            - PAPER_BILL
            - OTHER
        term:
          type: string
          description: |
            Term of the fee. `PERCENT_OF_BILL` implies a rate rather than a
            fixed amount; the other values are periodic or fixed.
          enum:
            - FIXED
            - 1_YEAR
            - 2_YEAR
            - 3_YEAR
            - 4_YEAR
            - 5_YEAR
            - PERCENT_OF_BILL
            - ANNUAL
            - DAILY
            - WEEKLY
            - MONTHLY
            - BIANNUAL
            - VARIABLE
        amount:
          type: string
          description: Fee amount (AmountString). Required unless `term` is `PERCENT_OF_BILL`.
        rate:
          type: string
          description: Fee rate (RateString). Required when `term` is `PERCENT_OF_BILL`.
        description:
          type: string
          description: Free-text description of the fee.

    EnergyPlanDiscountPercentOfBill:
      type: object
      description: Percent-of-bill discount variant. Populated when the parent's `methodUType` is `percentOfBill`.
      properties:
        rate:
          type: string
          description: Rate applied to the total bill amount (RateString).

    EnergyPlanDiscountPercentOfUse:
      type: object
      description: Percent-of-use discount variant. Populated when the parent's `methodUType` is `percentOfUse`.
      properties:
        rate:
          type: string
          description: Rate applied to the usage amount (RateString).

    EnergyPlanDiscountFixedAmount:
      type: object
      description: Fixed-amount discount variant. Populated when the parent's `methodUType` is `fixedAmount`.
      properties:
        amount:
          type: string
          description: Fixed discount amount (AmountString).

    EnergyPlanDiscountPercentOverThreshold:
      type: object
      description: Percent-over-threshold discount variant. Populated when the parent's `methodUType` is `percentOverThreshold`.
      properties:
        rate:
          type: string
          description: Rate applied to usage above the threshold (RateString).
        usageAmount:
          type: string
          description: Usage amount threshold above which the discount applies (AmountString).

    EnergyPlanDiscount:
      type: object
      description: |
        A discount that reduces the amount payable on a plan. Mirrors the
        Australian Consumer Data Standards `EnergyPlanDiscount` schema. One
        of the four variant sub-objects is populated per the `methodUType`
        discriminator.
      properties:
        displayName:
          type: string
          description: Display name of the discount.
        description:
          type: string
          description: Description of the discount.
        type:
          type: string
          description: Whether the discount is guaranteed or conditional.
          enum: [CONDITIONAL, GUARANTEED, OTHER]
        category:
          type: string
          description: Category of conditional discount. Mandatory when `type` is `CONDITIONAL`.
          enum: [PAY_ON_TIME, DIRECT_DEBIT, GUARANTEED_DISCOUNT, OTHER]
        endDate:
          type: string
          format: date
          description: Optional end date after which the discount is no longer available.
        methodUType:
          type: string
          description: |
            Discriminator selecting which of the four variant sub-objects
            (`percentOfBill`, `percentOfUse`, `fixedAmount`,
            `percentOverThreshold`) is populated.
          enum: [percentOfBill, percentOfUse, fixedAmount, percentOverThreshold]
        percentOfBill:
          $ref: "#/components/schemas/EnergyPlanDiscountPercentOfBill"
        percentOfUse:
          $ref: "#/components/schemas/EnergyPlanDiscountPercentOfUse"
        fixedAmount:
          $ref: "#/components/schemas/EnergyPlanDiscountFixedAmount"
        percentOverThreshold:
          $ref: "#/components/schemas/EnergyPlanDiscountPercentOverThreshold"

    EnergyPlanIncentive:
      type: object
      description: |
        An incentive offered under a plan (e.g. sign-up gift, account credit).
        Mirrors the Australian Consumer Data Standards `EnergyPlanIncentive`
        schema.
      properties:
        displayName:
          type: string
          description: Display name of the incentive.
        description:
          type: string
          description: Description of the incentive.
        category:
          type: string
          description: Category of incentive.
          enum: [GIFT, ACCOUNT_CREDIT, OTHER]
        eligibility:
          type: string
          description: Free-text display message describing any eligibility criteria.

    EnergyPlanSolarFeedInTariffSingleTariff:
      type: object
      description: Constant solar feed-in tariff. Populated when the parent's `tariffUType` is `singleTariff`.
      properties:
        amount:
          type: string
          description: Feed-in tariff amount (AmountString).

    EnergyPlanSolarFeedInTariffTimeVariation:
      type: object
      description: A time window during which a time-varying solar feed-in tariff applies.
      properties:
        days:
          type: array
          description: Days on which the tariff applies. At least one entry.
          items:
            type: string
            enum: [SUN, MON, TUE, WED, THU, FRI, SAT, PUBLIC_HOLIDAYS]
        startTime:
          type: string
          description: Start of the time-of-day period. If absent, assumes start-of-day (midnight).
        endTime:
          type: string
          description: End of the time-of-day period. If absent, assumes end-of-day.

    EnergyPlanSolarFeedInTariffTimeVarying:
      type: object
      description: |
        Time-varying solar feed-in tariff. Populated when the parent's
        `tariffUType` is `timeVaryingTariffs`.
      properties:
        type:
          type: string
          description: The charging time-period this tariff applies to. If absent, applies to all periods.
          enum: [PEAK, OFF_PEAK, SHOULDER]
        amount:
          type: string
          description: Feed-in tariff amount (AmountString).
        timeVariations:
          type: array
          description: Time periods for which this tariff is applicable.
          items:
            $ref: "#/components/schemas/EnergyPlanSolarFeedInTariffTimeVariation"

    EnergyPlanSolarFeedInTariff:
      type: object
      description: |
        Solar feed-in tariff paid to the customer for electricity exported to
        the grid. Mirrors the Australian Consumer Data Standards
        `EnergyPlanSolarFeedInTariff` schema.
      properties:
        displayName:
          type: string
          description: Name of the tariff.
        description:
          type: string
          description: Description of the tariff.
        scheme:
          type: string
          description: Scheme the tariff falls under.
          enum: [PREMIUM, OTHER]
        payerType:
          type: string
          description: Who pays the tariff.
          enum: [GOVERNMENT, RETAILER]
        tariffUType:
          type: string
          description: |
            Discriminator selecting whether the tariff is a single flat rate
            or varies by time-of-day/day-of-week.
          enum: [singleTariff, timeVaryingTariffs]
        singleTariff:
          $ref: "#/components/schemas/EnergyPlanSolarFeedInTariffSingleTariff"
        timeVaryingTariffs:
          $ref: "#/components/schemas/EnergyPlanSolarFeedInTariffTimeVarying"

    EnergyPlanDetail:
      type: object
      description: Detailed plan tariff, fees, discounts, and incentives. No PII.
      properties:
        fuelType:
          type: string
          description: Fuel type (e.g. ELECTRICITY, GAS).
        tariffPeriod:
          type: array
          description: Tariff periods with rates and blocks.
          items:
            $ref: "#/components/schemas/EnergyTariffPeriod"
        fees:
          type: array
          description: Plan fees and charges.
          items:
            $ref: "#/components/schemas/EnergyPlanFee"
        discounts:
          type: array
          description: Available discounts.
          items:
            $ref: "#/components/schemas/EnergyPlanDiscount"
        incentives:
          type: array
          description: Incentives (e.g. early-payment, loyalty).
          items:
            $ref: "#/components/schemas/EnergyPlanIncentive"
        solarFeedInTariff:
          type: array
          description: Solar feed-in tariff rates (if applicable).
          items:
            $ref: "#/components/schemas/EnergyPlanSolarFeedInTariff"

    EnergyPlan:
      type: object
      description: Plan/tariff details for an energy account. No PII.
      properties:
        planOverview:
          $ref: "#/components/schemas/EnergyPlanOverview"
          description: High-level plan overview.
        planDetail:
          $ref: "#/components/schemas/EnergyPlanDetail"
          description: Detailed tariff, fees, discounts, and incentives.

    EnergyAccount:
      allOf:
        - $ref: "#/components/schemas/ProviderRef"
        - type: object
          required: [accountId]
          properties:
            accountId:
              type: string
              description: Stable, provider-scoped account identifier.
            displayName:
              type: string
              description: Human-readable account name.
            status:
              type: string
              description: |
                Account status. One of: `ACTIVE`, `INACTIVE`, `CLOSED`,
                `PENDING` (setup pending).
            accountNumber:
              type: string
              description: Provider account reference number. Not PII.
            creationDate:
              type: string
              description: Account creation date as supplied by the provider (ISO date string).
            payloadVersion:
              type: integer
              default: 1
              description: |
                openfeed payload version. Currently always 1; reserved for
                future backwards-compatible additions.
            plans:
              type: array
              description: Plan/tariff details for this account (e.g. electricity plan, gas plan).
              items:
                $ref: "#/components/schemas/EnergyPlan"

    EnergyMeter:
      type: object
      description: |
        A service point (metering installation) attached to an energy
        account. In the Australian Consumer Data Standards this corresponds
        to a `servicePoint`.
      required: [meterId]
      properties:
        meterId:
          type: string
          description: Stable, provider-scoped service-point identifier.
        nationalMeteringId:
          type: string
          description: |
            National Metering Identifier (NMI) — the industry-standard,
            location-based identifier for an electricity service point.
        status:
          type: string
          description: |
            Current service-point status. Typical values per the Australian
            Consumer Data Standards: `ACTIVE`, `INACTIVE`, `DE_ENERGISED`,
            `EXTINCT`, `GREENFIELD`, `OFF`, `UNKNOWN`.
        detectedReadType:
          type: string
          description: |
            Whether this meter reports usage as daily totals or as
            fixed-length intervals (typically 30 min or 15 min).
          enum: [unknown, daily, interval]
        jurisdictionCode:
          type: string
          description: Jurisdiction code for the service point (e.g. NSW, VIC). Not PII.
        servicePointClassification:
          type: string
          description: Service point classification (e.g. SMALL, LARGE). Not PII.
        isGenerator:
          type: boolean
          description: Whether the service point has generation capability. Not PII.

    EnergyMeterReadBasic:
      type: object
      description: |
        Total-consumption meter read variant. Populated when the parent
        `EnergyMeterRead.readUType` is `basicRead`. Mirrors the Australian
        Consumer Data Standards `EnergyElectricityMeterReadBasic` schema.
      properties:
        quality:
          type: string
          description: Read quality (e.g. `ACTUAL`, `SUBSTITUTE`, `FINAL_SUBSTITUTE`, or `UNKNOWN`).
        value:
          type: number
          description: Meter read value. Positive = consumption; negative = export.

    EnergyMeterReadIntervalQuality:
      type: object
      description: |
        Quality flag for a contiguous range of interval reads whose quality
        is not `ACTUAL`. Mirrors the CDS
        `EnergyElectricityMeterReadIntervalReadQualities` schema.
      properties:
        startInterval:
          type: integer
          minimum: 1
          description: Start interval index for this quality flag (1-based).
        endInterval:
          type: integer
          minimum: 1
          description: End interval index for this quality flag.
        quality:
          type: string
          description: Quality of the reads in this interval range.
          enum: [SUBSTITUTE, FINAL_SUBSTITUTE]

    EnergyMeterReadInterval:
      type: object
      description: |
        Interval meter read variant. Populated when the parent
        `EnergyMeterRead.readUType` is `intervalRead`. Mirrors the Australian
        Consumer Data Standards `EnergyElectricityMeterReadInterval` schema.
      properties:
        readIntervalLength:
          type: integer
          minimum: 1
          description: Read interval length in minutes.
        aggregateValue:
          type: number
          description: |
            Aggregate sum of the interval read values. Positive = net
            consumption; negative = net export.
        intervalReads:
          type: array
          description: |
            Interval read values. Positive = consumption; negative = export.
            Each entry is a read for the interval of length
            `readIntervalLength` starting at midnight of the parent's
            `readStartDate`.
          items:
            type: number
        readQualities:
          type: array
          description: |
            Quality flags for reads that are not `ACTUAL`. Indices not
            specified are assumed to be `ACTUAL`.
          items:
            $ref: "#/components/schemas/EnergyMeterReadIntervalQuality"

    EnergyMeterRead:
      type: object
      description: |
        A meter read for a service point over a date range. Mirrors the
        Australian Consumer Data Standards `EnergyElectricityMeterRead`
        schema. One of `basicRead` or `intervalRead` is populated per the
        `readUType` discriminator.
      properties:
        servicePointId:
          type: string
          description: Stable service-point identifier.
        registerId:
          type: string
          description: Register ID of the meter register the reads come from.
        registerSuffix:
          type: string
          description: Register suffix of the meter register.
        meterId:
          type: string
          description: Meter identifier / serial number as it appears on the customer's bill.
        controlledLoad:
          type: boolean
          description: |
            Whether this register records energy under a Controlled Load
            regime. Absent = unknown.
        readStartDate:
          type: string
          format: date
          description: Date the meter reads start (AEST, assumed from midnight).
        readEndDate:
          type: string
          format: date
          description: |
            Date the meter reads end (AEST). If absent, equals
            `readStartDate` (single-day entry).
        unitOfMeasure:
          type: string
          description: |
            Unit of measure for the reads (e.g. `KWH`). Refer to Appendix B
            of the AEMO MDFF Specification NEM12/NEM13 v2.1 for the
            authoritative value list.
        readUType:
          type: string
          description: Discriminator selecting `basicRead` or `intervalRead`.
          enum: [basicRead, intervalRead]
        basicRead:
          $ref: "#/components/schemas/EnergyMeterReadBasic"
        intervalRead:
          $ref: "#/components/schemas/EnergyMeterReadInterval"

    EnergyDerDevice:
      type: object
      description: |
        A DER device (or group of like devices) attached to an AC connection.
        Mirrors the Australian Consumer Data Standards `EnergyElectricityDevice`
        schema.
      properties:
        deviceIdentifier:
          type: number
          description: |
            Identifier for a single DER device or a group of devices with the
            same attributes. Does not align with CDR ID permanence.
        count:
          type: integer
          minimum: 1
          description: Number of devices in the group.
        manufacturer:
          type: string
          description: Device manufacturer name. Absent = unknown.
        modelNumber:
          type: string
          description: Device model number. Absent = unknown.
        status:
          type: string
          description: Device status.
          enum: [ACTIVE, INACTIVE, DECOMMISSIONED]
        type:
          type: string
          description: Primary technology used in the DER device.
          enum: [FOSSIL, HYDRO, WIND, SOLAR_PV, RENEWABLE, GEOTHERMAL, STORAGE, OTHER]
        subtype:
          type: string
          description: |
            Sub-technology detail (e.g. battery chemistry, PV panel type, or
            whether a battery is in a vehicle-to-grid vehicle). Absent = other.
        nominalRatedCapacity:
          type: number
          description: Maximum output in kVA per unit in the group. `0` when unknown.
        nominalStorageCapacity:
          type: number
          description: |
            Maximum storage capacity in kVAh per storage module. Mandatory
            when `type` is `STORAGE`. `0` when unknown.

    EnergyDerAcConnection:
      type: object
      description: |
        A group of AC connections through which DER devices connect to the
        grid. Mirrors the Australian Consumer Data Standards
        `EnergyElectricityACConnection` schema.
      properties:
        connectionIdentifier:
          type: number
          description: AC connection ID as defined in the DER register. Does not align with CDR ID permanence.
        count:
          type: integer
          minimum: 1
          description: |
            Number of AC connections in the group (all connections in the
            group share the same attributes).
        equipmentType:
          type: string
          description: How the DER is connected. Absent = `OTHER`.
          enum: [INVERTER, OTHER]
        manufacturerName:
          type: string
          description: Inverter manufacturer name. Mandatory when `equipmentType` is `INVERTER`.
        inverterSeries:
          type: string
          description: Inverter series. Mandatory when `equipmentType` is `INVERTER`.
        inverterModelNumber:
          type: string
          description: Inverter model number. Mandatory when `equipmentType` is `INVERTER`.
        commissioningDate:
          type: string
          format: date
          description: Date the DER installation was commissioned.
        status:
          type: string
          description: Connection status.
          enum: [ACTIVE, INACTIVE, DECOMMISSIONED]
        inverterDeviceCapacity:
          type: number
          description: |
            Rated AC output power (kW). Mandatory when `equipmentType` is
            `INVERTER`. `0` when unknown.
        derDevices:
          type: array
          description: DER devices attached to this connection group.
          items:
            $ref: "#/components/schemas/EnergyDerDevice"

    EnergyDerProtectionMode:
      type: object
      description: |
        Central protection-and-control configuration for a DER installation.
        Present when `hasCentralProtectionControl` is true; one or more
        fields describe the active protection modes. Mirrors the Australian
        Consumer Data Standards `EnergyElectricityProtectionMode` schema.
      properties:
        exportLimitKva:
          type: number
          description: |
            Maximum power (kVA) that may be exported from the connection
            point to the grid. Absent = no limit.
        underFrequencyProtection:
          type: number
          description: Under-frequency protective function limit (Hz).
        underFrequencyProtectionDelay:
          type: number
          description: Under-frequency trip delay (seconds).
        overFrequencyProtection:
          type: number
          description: Over-frequency protective function limit (Hz).
        overFrequencyProtectionDelay:
          type: number
          description: Over-frequency trip delay (seconds).
        underVoltageProtection:
          type: number
          description: Under-voltage protective function limit (V).
        underVoltageProtectionDelay:
          type: number
          description: Under-voltage trip delay (seconds).
        overVoltageProtection:
          type: number
          description: Over-voltage protective function limit (V).
        overVoltageProtectionDelay:
          type: number
          description: Over-voltage trip delay (seconds).
        sustainedOverVoltage:
          type: number
          description: Sustained over-voltage protection limit (V).
        sustainedOverVoltageDelay:
          type: number
          description: Sustained over-voltage trip delay (seconds).
        frequencyRateOfChange:
          type: number
          description: Rate-of-change-of-frequency trip point (Hz/s).
        voltageVectorShift:
          type: number
          description: Voltage-vector-shift trip angle (degrees).
        interTripScheme:
          type: string
          description: Free-text description of the inter-trip scheme (e.g. "From local substation").
        neutralVoltageDisplacement:
          type: number
          description: Neutral voltage displacement trip voltage.

    EnergyUsage:
      type: object
      required: [meterId, intervalDate]
      properties:
        meterId:
          type: string
        intervalDate:
          type: string
          format: date
        reads:
          type: array
          description: Meter reads for the interval.
          items:
            $ref: "#/components/schemas/EnergyMeterRead"

    EnergyDer:
      type: object
      required: [meterId]
      description: |
        Distributed Energy Resources (DER) install configuration for a service
        point. Current-state config (not time series). No PII.
      properties:
        meterId:
          type: string
        acConnections:
          type: array
          description: AC connection details (inverter connections). No PII.
          items:
            $ref: "#/components/schemas/EnergyDerAcConnection"
        approvedCapacity:
          type: number
          description: Total approved capacity (kVA) of the installation. No PII.
        availablePhasesCount:
          type: integer
          description: Number of phases available at the connection point. No PII.
        installedPhasesCount:
          type: integer
          description: Number of phases with DER installed. No PII.
        islandableInstallation:
          type: boolean
          description: Whether the installation can operate islanded from the grid. No PII.
        hasCentralProtectionControl:
          type: boolean
          description: Whether central protection control is present. No PII.
        protectionMode:
          allOf:
            - $ref: "#/components/schemas/EnergyDerProtectionMode"
          description: Central protection-and-control configuration. Present when `hasCentralProtectionControl` is true.


    EnergyBillingTransaction:
      type: object
      required: [accountId]
      description: |
        A single energy billing transaction (usage/demand/onceOff/other/payment
        line item) for an account. Append-only history. `description` is a
        free-text billing label and is PAN/PII-scrubbed at ingestion.
      properties:
        accountId:
          type: string
          description: External (tokenised) account ID this transaction belongs to.
        executionDateTime:
          type: string
          format: date-time
          description: Date and time the transaction occurred. No PII.
        transactionUType:
          type: string
          description: Transaction sub-type (usage, demand, onceOff, otherCharges, payment). No PII.
        gst:
          type: number
          description: GST incurred in the transaction. No PII.
        amount:
          type: number
          description: Amount charged or credited for this transaction. No PII.
        description:
          type: string
          description: Optional free-text billing line-item label. PAN/PII-scrubbed at ingestion.
        invoiceNumber:
          type: string
          description: Invoice number this transaction is included in. No PII.
        meterId:
          type: string
          description: Meter the transaction applies to, when present. No PII.


    EnergyInvoice:
      type: object
      required: [invoiceNumber]
      description: |
        A single energy invoice for an account. No PII.
      properties:
        invoiceNumber:
          type: string
          description: Stable invoice number. No PII.
        issueDate:
          type: string
          format: date
          description: Date the invoice was issued. No PII.
        dueDate:
          type: string
          format: date
          description: Date the invoice is due. No PII.
        invoiceAmount:
          type: number
          description: Total amount of the invoice. No PII.
        gstAmount:
          type: number
          description: GST component of the invoice. No PII.
        balanceAtIssue:
          type: number
          description: Account balance at the time the invoice was issued. No PII.
        paymentStatus:
          type: string
          description: |
            Payment status of the invoice at time of retrieval. Typical
            values: `PAID`, `PARTIALLY_PAID`, `DUE`, `OVERDUE`.
        meterIds:
          type: array
          description: Meter IDs the invoice covers. No PII.
          items:
            type: string

    BankingBalance:
      type: object
      required: [accountId, currency]
      description: Current banking account balance, fetched on-demand from the provider (not part of the periodic sync).
      properties:
        accountId:
          type: string
          description: Account identifier from the provider.
        currentBalance:
          type: string
          description: Current account balance (ISO 20022 format).
        availableBalance:
          type: string
          description: Available balance for the account (ISO 20022 format).
        creditLimit:
          type: string
          description: Credit limit for credit/line-of-credit accounts (ISO 20022 format).
        amortisedLimitAmount:
          type: string
          description: Amortised limit amount for accounts with progressive draw-down limit.
        currency:
          type: string
          description: Currency for balance amounts (ISO 4217 format, e.g. AUD).

    BankingBalanceEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/BankingBalance" }

    EnergyBalance:
      type: object
      required: [accountId, currency]
      description: Current energy account balance, fetched on-demand from the provider (not part of the periodic sync).
      properties:
        accountId:
          type: string
          description: Account identifier from the provider.
        balance:
          type: number
          description: Current account balance (in account currency).
        currency:
          type: string
          description: Currency for balance amount (ISO 4217 format, e.g. AUD).

    EnergyBalanceEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/EnergyBalance" }

    RegisteredApp:
      type: object
      required: [appId, name, status]
      properties:
        appId:
          type: string
          format: uuid
          description: Unique identifier for the registered application
        name:
          type: string
          description: Display name of the application
        description:
          type: string
        logoUrl:
          type: string
        websiteUrl:
          type: string
        status:
          type: string
          enum: [PENDING, APPROVED, SUSPENDED]
        platformType:
          type: string
          enum: [OAUTH2]
          description: Integration platform type
        requestedScopes:
          type: array
          items:
            type: string
          description: Data scopes the app is permitted to request
        redirectUris:
          type: array
          items:
            type: string
          description: Allowed redirect URIs for the OAuth 2.0 authorization flow.

    # ---- Single-resource envelope wrappers ----
    RegisteredAppEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/RegisteredApp" }

    # ---- Grant index (lightweight list) ----
    GrantIndexItem:
      type: object
      description: |
        Lightweight grant index item returned by the app-scoped list endpoint.
        Contains only the stable identity fields needed for change detection.
      required: [id, revision]
      properties:
        id:
          type: string
          format: uuid
          description: Grant identifier.
        revision:
          type: integer
          format: int32
          description: Monotonic content revision counter.
        lastUpdated:
          type: string
          format: date-time
          description: ISO-8601 date-time of the last grant state change.

    GrantIndexListEnvelope:
      type: object
      required: [version, data, meta]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data:
          type: array
          items:
            $ref: "#/components/schemas/GrantIndexItem"
        meta:
          type: object
          required: [limit, offset, hasNext]
          properties:
            limit:
              type: integer
            offset:
              type: integer
            hasNext:
              type: boolean

    # ---- Grant RAR ----
    GrantRar:
      type: object
      description: |
        Resolved RAR (Rich Authorization Request) for a disclosure_grant_v1.
        Returned by /v1/app/grants and /v1/grants endpoints; reflects LIVE state.
      required: [type, grantId, userId, appId, grantRevision,
                 bankingAccountIds, energyAccountIds, grantStatus, meteringState]
      properties:
        type:
          type: string
          description: Grant variant discriminator. Always "disclosure_grant_v1".
          example: "disclosure_grant_v1"
        grantId:
          type: string
          format: uuid
        userId:
          type: string
          format: uuid
        appId:
          type: string
          format: uuid
        grantRevision:
          type: integer
          format: int32
          description: Monotonic content revision counter.
        bankingAccountIds:
          type: array
          items:
            type: string
            format: uuid
          description: Stable account_identity ids (BANKING) authorised under this grant.
        energyAccountIds:
          type: array
          items:
            type: string
            format: uuid
          description: Stable account_identity ids (ENERGY) authorised under this grant.
        grantStatus:
          type: string
          enum: [ACTIVE, REVOKED]
          description: Current grant status.
        meteringState:
          type: string
          enum: [ACTIVE, SUSPENDED]
          description: Current metering state.

    GrantRarEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/GrantRar" }

    BankingAccountDetailEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/BankingAccountDetail" }

    EnergyAccountEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/EnergyAccount" }

    EnergyMeterEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/EnergyMeter" }

    EnergyDerEnvelope:
      type: object
      required: [version, data]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        data: { $ref: "#/components/schemas/EnergyDer" }

    ApiVersion:
      type: string
      description: Payload schema discriminator.
      enum: ["V1"]

    PaginatedResponse:
      type: object
      required: [version, data, meta, links]
      properties:
        version: { $ref: "#/components/schemas/ApiVersion" }
        meta:
          type: object
          required: [limit, offset]
          properties:
            limit:
              type: integer
              description: Effective page size applied to this response.
            offset:
              type: integer
              description: Effective offset applied to this response.
        links:
          type: object
          required: [self]
          properties:
            self:
              type: string
              description: Absolute URL of the current page (defaults applied, other query params preserved).
            next:
              type: string
              description: |
                Absolute URL of the next page. Present ONLY when a further
                record exists (determined by peek-ahead). Absence means this is
                the last page.

paths:
  /v1/app:
    get:
      operationId: getSelfApp
      summary: Get details of the calling app
      description: |
        Returns the registration details for the app.

        Requires scope `openfeed-au:app:all:read`.
      tags: [App]
      security:
        - oauth2:
            - openfeed-au:app:all:read
      responses:
        "200":
          description: App details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegisteredAppEnvelope"
        "401":
          description: Missing or invalid token
        "404":
          description: App not found or not approved
  /v1/app/grants:
    get:
      operationId: listAppGrants
      summary: List grants belonging to the calling app
      description: |
        Returns a lightweight paginated index of grants belonging to the calling
        app. Each item contains only id, revision, and lastUpdated.

        Requires scope `openfeed-au:grant:all:list`.
      tags: [App]
      security:
        - oauth2:
            - openfeed-au:grant:all:list
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Grant index
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GrantIndexListEnvelope"
        "401":
          description: Missing or invalid token
        "404":
          description: App not found
  /v1/grants/{grantId}:
    get:
      operationId: queryGrant
      summary: Query a grant by id
      description: |
        Returns the grant detail based on the provided `grantId`.
        The token provided must be an access token bound to the specified grant.
      tags: ["Grant Management"]
      security:
        - oauth2:
            - openfeed-au:grant:self:query
      parameters:
        - name: grantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Resolved grant
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GrantRarEnvelope"
        "401":
          description: Missing or invalid token
        "404":
          description: Grant not found or does not belong to this app
    delete:
      operationId: revokeGrant
      summary: Revoke a grant by id
      description: |
        Revokes the specified grant by `grantId`.
        The token provided must be an access token bound to the specified grant.

        404 is returned on any mismatch. Returns 204 on success.

        Requires scope `openfeed-au:grant:self:revoke`.

      tags: ["Grant Management"]
      security:
        - oauth2:
            - openfeed-au:grant:self:revoke
      parameters:
        - name: grantId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Grant revoked
        "401":
          description: Missing or invalid token
        "404":
          description: Grant not found or does not belong to this app

  /v1/banking/accounts:
    get:
      operationId: listBankingAccounts
      description: |
        Offset-paginated list of banking accounts. Use `limit`/`offset`; the
        response `links.next` is present only while more records remain.
      summary: List all banking accounts across all connected providers
      tags: [Banking]
      security:
        - oauth2:
            - openfeed-au:data:banking:read
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Banking accounts list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/BankingAccount"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/banking/accounts/{accountId}:
    get:
      operationId: getBankingAccount
      summary: Get banking account detail
      tags: [Banking]
      security:
        - oauth2:
            - openfeed-au:data:banking:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Banking account detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankingAccountDetailEnvelope"

  /v1/banking/accounts/{accountId}/balance:
    get:
      operationId: getBankingAccountBalance
      summary: Get current banking account balance
      description: |
        Returns the current balance for a banking account, fetched on-demand
        from the provider. Responses are briefly cached (~15 min).
        Requires the account to be within the caller's grant consent scope.
      tags: [Banking]
      security:
        - oauth2:
            - openfeed-au:data:banking:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Current banking account balance
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankingBalanceEnvelope"
        "403":
          description: Account not in consent scope, or caller lacks permission
        "404":
          description: Account not found

  /v1/banking/accounts/{accountId}/transactions:
    get:
      operationId: listBankingTransactions
      description: |
        Offset-paginated transactions for a banking account. Use `limit`/`offset`;
        `oldestDate`/`newestDate` filters are preserved in `links.self`/`links.next`.
      summary: List transactions for a banking account
      tags: [Banking]
      security:
        - oauth2:
            - openfeed-au:data:banking:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: oldestDate
          in: query
          schema:
            type: string
            format: date
        - name: newestDate
          in: query
          schema:
            type: string
            format: date
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Transaction list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/BankingTransaction"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts:
    get:
      operationId: listEnergyAccounts
      description: |
        Offset-paginated list of energy accounts. Use `limit`/`offset`; the
        response `links.next` is present only while more records remain.
      summary: List all energy accounts across all connected providers
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Energy accounts list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/EnergyAccount"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts/{accountId}:
    get:
      operationId: getEnergyAccount
      summary: Get energy account detail
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Energy account detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnergyAccountEnvelope"

  /v1/energy/accounts/{accountId}/balance:
    get:
      operationId: getEnergyAccountBalance
      summary: Get current energy account balance
      description: |
        Returns the current balance for an energy account, fetched on-demand
        from the provider. Responses are briefly cached (~15 min).
        Requires the account to be within the caller's grant consent scope.
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Current energy account balance
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnergyBalanceEnvelope"
        "403":
          description: Account not in consent scope, or caller lacks permission
        "404":
          description: Account not found

  /v1/energy/accounts/{accountId}/meters:
    get:
      operationId: listEnergyMeters
      description: |
        Offset-paginated list of meters for an energy account. Use `limit`/`offset`; the
        response `links.next` is present only while more records remain.
      summary: List meters for an energy account
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Meters list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/EnergyMeter"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts/{accountId}/meters/{meterId}:
    get:
      operationId: getEnergyMeter
      summary: Get meter detail
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: meterId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Meter detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnergyMeterEnvelope"

  /v1/energy/accounts/{accountId}/meters/{meterId}/usage:
    get:
      operationId: getEnergyMeterUsage
      description: |
        Offset-paginated usage for a meter. Use `limit`/`offset`;
        `oldestDate`/`newestDate` filters are preserved in `links.self`/`links.next`.
      summary: Get usage data for a meter
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: meterId
          in: path
          required: true
          schema:
            type: string
        - name: oldestDate
          in: query
          schema:
            type: string
            format: date
        - name: newestDate
          in: query
          schema:
            type: string
            format: date
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Usage data
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/EnergyUsage"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts/{accountId}/meters/{meterId}/der:
    get:
      operationId: getEnergyMeterDer
      summary: Get DER (Distributed Energy Resources) configuration for a meter
      description: |
        Current-state DER install configuration for a meter.
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: meterId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: DER configuration
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnergyDerEnvelope"
        "404":
          description: Meter not found, or no DER configuration recorded for it.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts/{accountId}/billing:
    get:
      operationId: getEnergyAccountBilling
      summary: Get billing transactions for an energy account
      description: |
        Offset-paginated billing transactions for an account, sorted by
        execution date/time descending.
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Billing transactions
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/EnergyBillingTransaction"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Account not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/energy/accounts/{accountId}/invoices:
    get:
      operationId: getEnergyAccountInvoices
      summary: Get invoices for an energy account
      description: |
        Offset-paginated invoices for an account, sorted by issue date
        descending.
      tags: [Energy]
      security:
        - oauth2:
            - openfeed-au:data:energy:read
      parameters:
        - name: accountId
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 1000
            minimum: 1
            maximum: 1000
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
            minimum: 0
      responses:
        "200":
          description: Invoices
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginatedResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/EnergyInvoice"
        "400":
          description: Invalid limit/offset, or offset past the end (code=no_records_found_at_offset_limit).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Account not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
