openapi: 3.0.0
info:
  title: Otark BRP API
  description: API for Balancing Responsible Parties (BRPs) to manage contracts, transactions, nominations, and customers on the Otark platform.
  version: "1.0.0"
  contact: {}
servers:
  - url: https://api.otark.energy
    description: Production
tags:
  - name: Contracts
    description: Manage energy contracts (PPA, day-ahead, etc.)
  - name: Transactions
    description: Contractual energy volumes between buyer and seller
  - name: Nominations
    description: Net saldo aggregated by balance group
  - name: Customers
    description: Manage customers assigned to the BRP
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
  parameters:
    LimitParam:
      name: limit
      in: query
      description: Maximum number of items per page
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 10
    AfterParam:
      name: after
      in: query
      description: Cursor for the next page — pass the `next_cursor` value from the previous response
      schema:
        type: string
        example: con_a1b2c3d4
    DeliveryStartParam:
      name: delivery_start
      in: query
      description: "Filter: delivery start >= this value (ISO 8601)"
      schema:
        type: string
        format: date-time
        example: "2026-01-01T00:00:00Z"
    DeliveryEndParam:
      name: delivery_end
      in: query
      description: "Filter: delivery end <= this value (ISO 8601)"
      schema:
        type: string
        format: date-time
        example: "2026-03-31T23:45:00Z"
    DeliveryDateParam:
      name: delivery_date
      in: query
      description: Filter by delivery date (shorthand for full-day range)
      schema:
        type: string
        format: date
        example: "2026-01-15"
    SlotNumberFromParam:
      name: slot_number_from
      in: query
      description: "Filter: slot number >= this value (1–100)"
      schema:
        type: integer
        minimum: 1
        maximum: 100
    SlotNumberToParam:
      name: slot_number_to
      in: query
      description: "Filter: slot number <= this value (1–100)"
      schema:
        type: integer
        minimum: 1
        maximum: 100
    IncludeAssetsParam:
      name: include_assets
      in: query
      description: Include a deduplicated `assets` array in the response, containing all assets referenced by the returned transactions
      schema:
        type: string
        enum:
          - "true"
          - "false"
        default: "false"
  headers:
    X-RateLimit-Limit:
      description: Maximum number of requests allowed per window
      schema:
        type: integer
        example: 300
    X-RateLimit-Remaining:
      description: Remaining requests in the current window
      schema:
        type: integer
        example: 299
    X-RateLimit-Reset:
      description: Seconds until the rate limit window resets
      schema:
        type: integer
        example: 60
  schemas:
    Pagination:
      type: object
      properties:
        limit:
          type: integer
          description: Maximum items per page
          example: 10
        has_more:
          type: boolean
          description: Whether more records exist after the last returned record
          example: true
        next_cursor:
          type: string
          nullable: true
          description: Cursor to pass as the `after` query parameter to fetch the next page. Null when there are no more pages.
          example: txn_k8m2p4q7r1
      required:
        - limit
        - has_more
        - next_cursor
    Problem:
      type: object
      description: "Error response following [RFC 9457 — Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457)."
      properties:
        type:
          type: string
          format: uri
          description: Absolute URI identifying the problem class
          example: https://brp.otark.team/errors/balance_group_tso_not_enabled
        title:
          type: string
          description: Short human-readable label (stable across occurrences of the same type)
          example: Balance Group TSO Not Enabled
        status:
          type: integer
          description: HTTP status code
          example: 400
        detail:
          type: string
          description: Human-readable explanation for this specific occurrence
          example: The requested TSO is not enabled for this balance group. Enable it via the balance group settings first.
        instance:
          type: string
          description: URI identifying the specific request
          example: /v1/customers/cust_r8s9t0u1
        errors:
          type: array
          description: Field-level validation errors (present on validation failures)
          items:
            $ref: "#/components/schemas/ProblemFieldError"
      required:
        - type
        - title
        - status
    ProblemFieldError:
      type: object
      description: A single field-level validation error
      properties:
        field:
          type: string
          description: JSON path of the field that caused the error
          example: balance_group.tso
        code:
          type: string
          description: "Machine-readable error code: `unknown_field`, `read_only_field`, `required`, `invalid_type`, `invalid_enum_value`, `invalid_format`, `invalid_literal`, `value_too_small`, `value_too_large`, or `validation_failed`"
          example: invalid_enum_value
        message:
          type: string
          description: Human-readable description of the issue
          example: "Invalid enum value. Expected 'DE_AMPRION' | 'DE_TENNET' | 'DE_TRANSNET_BW' | 'DE_50HERTZ', received 'INVALID'"
      required:
        - code
        - message
    Counterparty:
      type: object
      description: A counterparty identified by EIC code
      properties:
        name:
          type: string
          description: Company or entity name
          example: GreenCo Energy BV
        eic:
          type: string
          description: EIC code (balance group)
          example: 11YGREENENERGY-Z
        tso:
          type: string
          description: TSO responsible for the balance group
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_TENNET
      required:
        - name
        - eic
        - tso
    Asset:
      type: object
      description: A generating asset
      properties:
        id:
          type: string
          description: Unique asset identifier
          example: ast_w1x2y3z4
        name:
          type: string
          description: Display name of the generating asset
          example: Zonnepark De Wilgen
        nominal_power:
          type: number
          description: Nominal power capacity in MW
          example: 25.0
        technology:
          type: string
          description: Generation technology
          enum:
            - solar
            - wind_onshore
            - wind_offshore
          example: solar
        tso:
          type: string
          description: TSO responsible for the asset's grid connection
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_TENNET
      required:
        - id
        - name
        - nominal_power
        - technology
        - tso
    Contract:
      type: object
      description: An energy contract. Contracts are polymorphic — the schema varies by `type`.
      properties:
        id:
          type: string
          description: Internal unique contract identifier
          example: con_a1b2c3d4
        external_id:
          type: string
          description: External reference identifier
          example: PPA-2025-0042
        type:
          type: string
          description: Contract type
          enum:
            - ppa
            - day_ahead
            - intraday
          example: ppa
        status:
          type: string
          description: Contract status
          enum:
            - pending
            - in_progress
            - completed
          example: in_progress
        delivery_start:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 delivery start (UTC)
          example: "2026-01-01T00:00:00Z"
        delivery_end:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 delivery end (UTC)
          example: "2026-03-31T23:45:00Z"
        seller:
          $ref: "#/components/schemas/Counterparty"
        buyer:
          $ref: "#/components/schemas/Counterparty"
        ppa_type:
          type: string
          nullable: true
          description: PPA pricing/delivery type (only present when `type` is `ppa`)
          enum:
            - forecasted
            - produced
            - consumed
            - baseload
            - shaped
            - peakload
            - indexed
          example: indexed
        period:
          type: string
          nullable: true
          description: Contract period display name (only present when `type` is `ppa`)
          example: Q1-2026
        delivery_profile:
          type: string
          nullable: true
          description: Delivery profile name (only present when `type` is `ppa`)
          example: ENWEX Solar 2026
        asset:
          description: The generating asset (only present when `type` is `ppa` and an asset is assigned)
          allOf:
            - $ref: "#/components/schemas/Asset"
        created_at:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 creation timestamp
          example: "2024-11-20T10:00:00Z"
      required:
        - id
        - external_id
        - type
        - status
        - delivery_start
        - delivery_end
        - seller
        - buyer
        - created_at
    ContractList:
      type: object
      properties:
        contracts:
          type: array
          description: List of contracts
          items:
            $ref: "#/components/schemas/Contract"
        pagination:
          $ref: "#/components/schemas/Pagination"
      required:
        - contracts
        - pagination
    TransactionSender:
      type: object
      description: The sending party of a transaction
      properties:
        eic:
          type: string
          description: EIC code (balance group) of the sender
          example: 11YWINDPARKNO--A
        asset_id:
          type: string
          nullable: true
          description: Asset identifier (use `include_assets=true` to sideload full asset details)
          example: ast_w1x2y3z4
        tso:
          type: string
          description: Sender's TSO
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_TENNET
      required:
        - eic
        - asset_id
        - tso
    TransactionReceiver:
      type: object
      description: The receiving party of a transaction
      properties:
        eic:
          type: string
          description: EIC code (balance group) of the receiver
          example: 11YGREENENERGY-Z
        tso:
          type: string
          description: Receiver's TSO
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_TENNET
      required:
        - eic
        - tso
    Transaction:
      type: object
      description: Represents the contractual energy volumes to be transferred between buyer and seller under a contract. Transactions are immutable — corrections produce a new version that supersedes the previous one.
      properties:
        id:
          type: string
          description: Unique transaction identifier
          example: txn_k8m2p4q7r1
        type:
          type: string
          description: Transaction type
          enum:
            - ppa
          example: ppa
        contract_id:
          type: string
          description: Parent contract identifier
          example: con_a1b2c3d4
        status:
          type: string
          description: Transaction status
          enum:
            - valid
            - invalid
            - superseded
          example: valid
        version:
          type: integer
          description: Version number (starts at 1, increments on correction)
          example: 2
        previous_transaction_id:
          type: string
          nullable: true
          description: ID of the transaction this version supersedes
          example: txn_j5n3w8v2x6
        sender:
          $ref: "#/components/schemas/TransactionSender"
        receiver:
          $ref: "#/components/schemas/TransactionReceiver"
        delivery_start:
          type: string
          format: date-time
          description: ISO 8601 delivery period start (UTC)
          example: "2026-01-15T14:00:00Z"
        delivery_end:
          type: string
          format: date-time
          description: ISO 8601 delivery period end (UTC)
          example: "2026-01-15T14:15:00Z"
        slot_number:
          type: integer
          description: Quarter-hour slot number within the delivery day (1–96, or up to 100 on DST days)
          minimum: 1
          maximum: 100
          example: 57
        volume:
          type: number
          description: Energy volume in MWh (3 decimal places)
          example: 12.500
        created_at:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: "2026-01-14T18:00:00Z"
      required:
        - id
        - type
        - contract_id
        - status
        - version
        - sender
        - receiver
        - delivery_start
        - delivery_end
        - slot_number
        - volume
        - created_at
    TransactionList:
      type: object
      properties:
        transactions:
          type: array
          description: List of transactions
          items:
            $ref: "#/components/schemas/Transaction"
        pagination:
          $ref: "#/components/schemas/Pagination"
        assets:
          type: array
          description: Deduplicated list of assets referenced by the returned transactions (only present when `include_assets=true`)
          items:
            $ref: "#/components/schemas/Asset"
      required:
        - transactions
        - pagination
    TransactionHistoryList:
      type: object
      properties:
        transactions:
          type: array
          description: Version history ordered from newest to oldest
          items:
            $ref: "#/components/schemas/Transaction"
        assets:
          type: array
          description: Deduplicated list of assets referenced by the returned transactions (only present when `include_assets=true`)
          items:
            $ref: "#/components/schemas/Asset"
      required:
        - transactions
    BulkTransactionList:
      type: object
      properties:
        transactions:
          type: array
          description: List of transactions (non-existent or inaccessible IDs are silently omitted)
          items:
            $ref: "#/components/schemas/Transaction"
        assets:
          type: array
          description: Deduplicated list of assets referenced by the returned transactions (only present when `include_assets=true`)
          items:
            $ref: "#/components/schemas/Asset"
      required:
        - transactions
    NominationCounterparty:
      type: object
      description: The counterparty in a nomination (Otark acts as intermediary)
      properties:
        name:
          type: string
          description: Counterparty name
          example: Otark
        eic:
          type: string
          description: EIC code
          example: 11YOTARK------Z
      required:
        - name
        - eic
    NominationSlot:
      type: object
      description: A delivery time slot within a nomination
      properties:
        delivery_start:
          type: string
          format: date-time
          description: ISO 8601 slot start (UTC)
          example: "2026-01-15T14:00:00Z"
        delivery_end:
          type: string
          format: date-time
          description: ISO 8601 slot end (UTC)
          example: "2026-01-15T14:15:00Z"
        slot_number:
          type: integer
          description: Quarter-hour slot number within the delivery day (1–96, or up to 100 on DST days)
          minimum: 1
          maximum: 100
          example: 57
        amount:
          type: number
          description: Nominated energy volume in MWh (3 decimal places)
          example: 12.500
        matched_amount:
          type: number
          nullable: true
          description: Confirmed/matched volume in MWh (null until matched)
          example: 12.500
      required:
        - delivery_start
        - delivery_end
        - slot_number
        - amount
    Nomination:
      type: object
      description: The net saldo of valid transactions, aggregated by balance group and delivery period. Nominations are immutable — corrections produce a new version.
      properties:
        id:
          type: string
          description: Unique nomination identifier
          example: nom_t4u5v6w7x8
        status:
          type: string
          description: Nomination status
          enum:
            - pending
            - partial_match
            - match
            - superseded
          example: match
        version:
          type: integer
          description: Version number (starts at 1, increments on correction)
          example: 1
        previous_nomination_id:
          type: string
          nullable: true
          description: ID of the nomination this version supersedes
          example: null
        gate_closure:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 gate closure deadline
          example: "2026-01-14T14:30:00Z"
        confirmed_at:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp when the nomination was confirmed
          example: "2026-01-14T15:00:00Z"
        direction:
          type: string
          description: Energy direction from the BRP's perspective
          enum:
            - out
            - in
          example: out
        eic:
          type: string
          description: EIC code (balance group) of the BRP
          example: 11YWINDPARKNO--A
        tso:
          type: string
          description: BRP's TSO
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_TENNET
        sent_at:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp when sent to the TSO
          example: "2026-01-14T14:35:00Z"
        counterparty:
          $ref: "#/components/schemas/NominationCounterparty"
        slots:
          type: array
          description: Delivery time slots with volumes (only present when `include_slots=true` on list endpoint; always present on detail/bulk/history endpoints)
          items:
            $ref: "#/components/schemas/NominationSlot"
        created_at:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: "2026-01-14T14:30:00Z"
      required:
        - id
        - status
        - version
        - gate_closure
        - direction
        - eic
        - tso
        - counterparty
        - created_at
    NominationList:
      type: object
      properties:
        nominations:
          type: array
          description: List of nominations
          items:
            $ref: "#/components/schemas/Nomination"
        pagination:
          $ref: "#/components/schemas/Pagination"
      required:
        - nominations
        - pagination
    NominationHistoryList:
      type: object
      properties:
        nominations:
          type: array
          description: Version history ordered from newest to oldest
          items:
            $ref: "#/components/schemas/Nomination"
      required:
        - nominations
    BulkNominationList:
      type: object
      properties:
        nominations:
          type: array
          description: List of nominations (non-existent or inaccessible IDs are silently omitted)
          items:
            $ref: "#/components/schemas/Nomination"
      required:
        - nominations
    BalanceGroup:
      type: object
      description: A balance group assignment
      properties:
        eic:
          type: string
          description: EIC code (balance group)
          example: 11YSOLARDACH--A
        tso:
          type: string
          description: TSO
          enum:
            - DE_AMPRION
            - DE_TENNET
            - DE_TRANSNET_BW
            - DE_50HERTZ
          example: DE_AMPRION
      required:
        - eic
        - tso
    Customer:
      type: object
      description: A customer assigned to the BRP
      properties:
        id:
          type: string
          description: Unique customer identifier
          example: cust_r8s9t0u1
        name:
          type: string
          description: Customer display name
          example: SolarDach GmbH
        status:
          type: string
          description: Customer status
          enum:
            - pending
            - active
            - deactivated
          example: active
        balance_group:
          nullable: true
          allOf:
            - $ref: "#/components/schemas/BalanceGroup"
        metadata:
          type: object
          description: BRP-defined key-value pairs (free-form)
          additionalProperties:
            type: string
          example:
            customer_number: KD-2026-0815
            cost_center: CC-4200
            region: NRW
        assigned_at:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the customer was assigned
          example: "2026-01-10T09:00:00Z"
        activated_at:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp when the customer was activated
          example: "2026-01-10T11:30:00Z"
        created_at:
          type: string
          format: date-time
          description: ISO 8601 creation timestamp
          example: "2026-01-10T09:00:00Z"
      required:
        - id
        - name
        - status
        - balance_group
        - metadata
        - assigned_at
        - created_at
    CustomerList:
      type: object
      properties:
        customers:
          type: array
          description: List of customers
          items:
            $ref: "#/components/schemas/Customer"
        pagination:
          $ref: "#/components/schemas/Pagination"
      required:
        - customers
        - pagination
    CustomerUpdate:
      type: object
      description: Partial update for a customer. Metadata is merged — only provided keys are added or overwritten. Set a key to `null` to remove it. Sending read-only fields (`id`, `name`, `assigned_at`, `activated_at`, `created_at`) returns a `read_only_field` error.
      properties:
        status:
          type: string
          description: New customer status
          enum:
            - pending
            - active
            - deactivated
        balance_group:
          $ref: "#/components/schemas/BalanceGroup"
        metadata:
          type: object
          description: Key-value pairs to merge into existing metadata
          additionalProperties:
            type: string
            nullable: true
          example:
            customer_number: KD-2026-0815
            cost_center: CC-4200
    BulkTransactionIdsRequest:
      type: object
      properties:
        ids:
          type: array
          description: List of transaction IDs to retrieve (max 100)
          items:
            type: string
          minItems: 1
          maxItems: 100
          example:
            - txn_k8m2p4q7r1
            - txn_j5n3w8v2x6
            - txn_h2b7f9d4g3
        include_assets:
          type: boolean
          description: Include a deduplicated `assets` array in the response
          default: false
      required:
        - ids
    BulkNominationIdsRequest:
      type: object
      properties:
        ids:
          type: array
          description: List of nomination IDs to retrieve (max 100)
          items:
            type: string
          minItems: 1
          maxItems: 100
          example:
            - nom_t4u5v6w7x8
            - nom_q1r2s3t4u5
      required:
        - ids
  responses:
    NotFound:
      description: Resource does not exist or caller has no access
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/customer_not_found
            title: Customer Not Found
            status: 404
            instance: /v1/customers/cust_r8s9t0u1
    BadRequest:
      description: Invalid request — validation error or business rule violation
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/validation
            title: Validation Failed
            status: 400
            instance: /v1/customers/cust_r8s9t0u1
            errors:
              - field: balance_group.tso
                code: invalid_enum_value
                message: "Invalid enum value. Expected 'DE_AMPRION' | 'DE_TENNET' | 'DE_TRANSNET_BW' | 'DE_50HERTZ', received 'INVALID'"
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/invalid_api_key
            title: Invalid API Key
            status: 401
    Forbidden:
      description: API key lacks required scopes
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/insufficient_scopes
            title: Insufficient API Key Scopes
            status: 403
            detail: "Missing scope: customers:write. Please create a new API key with the required scopes."
    Conflict:
      description: State conflict — the operation cannot be completed in the current state
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/already_active
            title: Customer Already Active
            status: 409
    RateLimited:
      description: Rate limit exceeded
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
          example:
            type: https://brp.otark.team/errors/rate_limited
            title: Rate Limited
            status: 429
paths:
  /v1/contracts:
    get:
      operationId: listContracts
      summary: List contracts
      description: "List contracts accessible to the authenticated BRP. Supports filtering by status, type, EIC code, delivery period, and active date.\n\nRequired scope: `contracts:read`"
      tags:
        - Contracts
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - contracts:read
      parameters:
        - name: status
          in: query
          description: Filter by contract status
          schema:
            type: string
            enum:
              - pending
              - in_progress
              - completed
        - name: type
          in: query
          description: Filter by contract type
          schema:
            type: string
            enum:
              - ppa
              - day_ahead
              - intraday
        - name: eic
          in: query
          description: Filter by buyer or seller EIC code
          schema:
            type: string
            example: 11YGREENENERGY-Z
        - $ref: "#/components/parameters/DeliveryStartParam"
        - $ref: "#/components/parameters/DeliveryEndParam"
        - name: active_on
          in: query
          description: Filter contracts active on this date
          schema:
            type: string
            format: date
            example: "2026-01-15"
        - $ref: "#/components/parameters/LimitParam"
        - $ref: "#/components/parameters/AfterParam"
      responses:
        "200":
          description: Contracts list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ContractList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/contracts/{contract_id}:
    get:
      operationId: getContract
      summary: Get contract
      description: "Retrieve a single contract by ID.\n\nRequired scope: `contracts:read`"
      tags:
        - Contracts
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - contracts:read
      parameters:
        - name: contract_id
          in: path
          required: true
          description: Contract identifier
          schema:
            type: string
            example: con_a1b2c3d4
      responses:
        "200":
          description: Contract details
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Contract"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/contracts/{contract_id}/transactions:
    get:
      operationId: listContractTransactions
      summary: List contract transactions
      description: "List transactions under a specific contract. Same filters as the global transactions endpoint, minus `contract_id` and `type`.\n\nRequired scopes: `contracts:read`, `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - contracts:read
        - transactions:read
      parameters:
        - name: contract_id
          in: path
          required: true
          description: Contract identifier
          schema:
            type: string
            example: con_a1b2c3d4
        - name: status
          in: query
          description: Filter by transaction status
          schema:
            type: string
            enum:
              - valid
              - invalid
              - superseded
        - name: sender_eic
          in: query
          description: Filter by sender EIC code
          schema:
            type: string
            example: 11YWINDPARKNO--A
        - name: receiver_eic
          in: query
          description: Filter by receiver EIC code
          schema:
            type: string
            example: 11YGREENENERGY-Z
        - $ref: "#/components/parameters/DeliveryDateParam"
        - $ref: "#/components/parameters/DeliveryStartParam"
        - $ref: "#/components/parameters/DeliveryEndParam"
        - $ref: "#/components/parameters/SlotNumberFromParam"
        - $ref: "#/components/parameters/SlotNumberToParam"
        - $ref: "#/components/parameters/IncludeAssetsParam"
        - $ref: "#/components/parameters/LimitParam"
        - $ref: "#/components/parameters/AfterParam"
      responses:
        "200":
          description: Transactions list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/transactions:
    get:
      operationId: listTransactions
      summary: List all transactions
      description: "List all transactions across contracts. Accepts the same filters as the contract-scoped endpoint, plus contract_id and type filters.\n\nRequired scope: `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - transactions:read
      parameters:
        - name: contract_id
          in: query
          description: Filter by contract
          schema:
            type: string
            example: con_a1b2c3d4
        - name: type
          in: query
          description: Filter by transaction type
          schema:
            type: string
            enum:
              - ppa
        - name: status
          in: query
          description: Filter by transaction status
          schema:
            type: string
            enum:
              - valid
              - invalid
              - superseded
        - name: sender_eic
          in: query
          description: Filter by sender EIC code
          schema:
            type: string
            example: 11YWINDPARKNO--A
        - name: receiver_eic
          in: query
          description: Filter by receiver EIC code
          schema:
            type: string
            example: 11YGREENENERGY-Z
        - $ref: "#/components/parameters/DeliveryDateParam"
        - $ref: "#/components/parameters/DeliveryStartParam"
        - $ref: "#/components/parameters/DeliveryEndParam"
        - $ref: "#/components/parameters/SlotNumberFromParam"
        - $ref: "#/components/parameters/SlotNumberToParam"
        - $ref: "#/components/parameters/IncludeAssetsParam"
        - $ref: "#/components/parameters/LimitParam"
        - $ref: "#/components/parameters/AfterParam"
      responses:
        "200":
          description: Transactions list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/transactions/{transaction_id}:
    get:
      operationId: getTransaction
      summary: Get transaction
      description: "Retrieve a single transaction by ID.\n\nRequired scope: `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - transactions:read
      parameters:
        - name: transaction_id
          in: path
          required: true
          description: Transaction identifier
          schema:
            type: string
            example: txn_k8m2p4q7r1
      responses:
        "200":
          description: Transaction details
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/transactions/{transaction_id}/history:
    get:
      operationId: getTransactionHistory
      summary: Get transaction history
      description: "Retrieve the full version history of a transaction, following the `previous_transaction_id` chain. Returns all versions ordered from newest to oldest.\n\nRequired scope: `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - transactions:read
      parameters:
        - name: transaction_id
          in: path
          required: true
          description: Transaction identifier
          schema:
            type: string
            example: txn_k8m2p4q7r1
        - $ref: "#/components/parameters/IncludeAssetsParam"
      responses:
        "200":
          description: Transaction version history
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionHistoryList"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/transactions/bulk:
    get:
      operationId: bulkGetTransactions
      summary: Bulk get transactions
      description: "Retrieve multiple transactions by ID in a single request. Limited to 100 IDs via query parameter. Non-existent or inaccessible IDs are silently omitted.\n\nRequired scope: `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - transactions:read
      parameters:
        - name: ids
          in: query
          required: true
          description: Comma-separated list of transaction IDs (max 100)
          schema:
            type: string
            example: txn_k8m2p4q7r1,txn_j5n3w8v2x6,txn_h2b7f9d4g3
        - $ref: "#/components/parameters/IncludeAssetsParam"
      responses:
        "200":
          description: Transactions list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkTransactionList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
    post:
      operationId: bulkPostTransactions
      summary: Bulk get transactions (POST)
      description: "Retrieve multiple transactions by ID using a request body. Use this for large ID sets that exceed the GET query parameter limit. Non-existent or inaccessible IDs are silently omitted.\n\nRequired scope: `transactions:read`"
      tags:
        - Transactions
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - transactions:read
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BulkTransactionIdsRequest"
      responses:
        "200":
          description: Transactions list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkTransactionList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/nominations:
    get:
      operationId: listNominations
      summary: List nominations
      description: "List nominations accessible to the authenticated BRP.\n\nRequired scope: `nominations:read`"
      tags:
        - Nominations
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - nominations:read
      parameters:
        - name: status
          in: query
          description: Filter by nomination status
          schema:
            type: string
            enum:
              - pending
              - partial_match
              - match
              - superseded
        - name: eic
          in: query
          description: Filter by customer EIC code
          schema:
            type: string
            example: 11YWINDPARKNO--A
        - $ref: "#/components/parameters/DeliveryDateParam"
        - $ref: "#/components/parameters/DeliveryStartParam"
        - $ref: "#/components/parameters/DeliveryEndParam"
        - $ref: "#/components/parameters/SlotNumberFromParam"
        - $ref: "#/components/parameters/SlotNumberToParam"
        - name: include_slots
          in: query
          description: Include the `slots` array in the response (default false). When false, the slots field is omitted.
          schema:
            type: string
            enum:
              - "true"
              - "false"
            default: "false"
        - $ref: "#/components/parameters/LimitParam"
        - $ref: "#/components/parameters/AfterParam"
      responses:
        "200":
          description: Nominations list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NominationList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/nominations/{nomination_id}:
    get:
      operationId: getNomination
      summary: Get nomination
      description: "Retrieve a single nomination with its counterparties and slots.\n\nRequired scope: `nominations:read`"
      tags:
        - Nominations
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - nominations:read
      parameters:
        - name: nomination_id
          in: path
          required: true
          description: Nomination identifier
          schema:
            type: string
            example: nom_t4u5v6w7x8
      responses:
        "200":
          description: Nomination details
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Nomination"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/nominations/{nomination_id}/history:
    get:
      operationId: getNominationHistory
      summary: Get nomination history
      description: "Retrieve the full version history of a nomination, following the `previous_nomination_id` chain. Returns all versions ordered from newest to oldest.\n\nRequired scope: `nominations:read`"
      tags:
        - Nominations
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - nominations:read
      parameters:
        - name: nomination_id
          in: path
          required: true
          description: Nomination identifier
          schema:
            type: string
            example: nom_t4u5v6w7x8
      responses:
        "200":
          description: Nomination version history
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NominationHistoryList"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/nominations/bulk:
    get:
      operationId: bulkGetNominations
      summary: Bulk get nominations
      description: "Retrieve multiple nominations by ID in a single request. Limited to 100 IDs via query parameter. Non-existent or inaccessible IDs are silently omitted.\n\nRequired scope: `nominations:read`"
      tags:
        - Nominations
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - nominations:read
      parameters:
        - name: ids
          in: query
          required: true
          description: Comma-separated list of nomination IDs (max 100)
          schema:
            type: string
            example: nom_t4u5v6w7x8,nom_q1r2s3t4u5
      responses:
        "200":
          description: Nominations list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkNominationList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
    post:
      operationId: bulkPostNominations
      summary: Bulk get nominations (POST)
      description: "Retrieve multiple nominations by ID using a request body. Use this for large ID sets that exceed the GET query parameter limit. Non-existent or inaccessible IDs are silently omitted.\n\nRequired scope: `nominations:read`"
      tags:
        - Nominations
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - nominations:read
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BulkNominationIdsRequest"
      responses:
        "200":
          description: Nominations list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BulkNominationList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/customers:
    get:
      operationId: listCustomers
      summary: List customers
      description: "List customers assigned to the authenticated BRP.\n\nRequired scope: `customers:read`"
      tags:
        - Customers
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - customers:read
      parameters:
        - name: status
          in: query
          description: Filter by customer status
          schema:
            type: string
            enum:
              - pending
              - active
              - deactivated
        - name: search
          in: query
          description: Free-text search on name or metadata values
          schema:
            type: string
        - $ref: "#/components/parameters/LimitParam"
        - $ref: "#/components/parameters/AfterParam"
      responses:
        "200":
          description: Customers list
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerList"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /v1/customers/{customer_id}:
    get:
      operationId: getCustomer
      summary: Get customer
      description: "Retrieve a single customer by ID.\n\nRequired scope: `customers:read`"
      tags:
        - Customers
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - customers:read
      parameters:
        - name: customer_id
          in: path
          required: true
          description: Customer identifier
          schema:
            type: string
            example: cust_r8s9t0u1
      responses:
        "200":
          description: Customer details
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Customer"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
    patch:
      operationId: updateCustomer
      summary: Update customer
      description: "Update a customer's status, balance group, or metadata. Used to activate a pending customer, deactivate an existing one, change their balance group, or manage custom metadata. Metadata is merged on update — only provided keys are added or overwritten. Set a key's value to `null` to remove it.\n\nRequired scope: `customers:write`"
      tags:
        - Customers
      security:
        - ApiKeyAuth: []
      x-required-scopes:
        - customers:write
      parameters:
        - name: customer_id
          in: path
          required: true
          description: Customer identifier
          schema:
            type: string
            example: cust_r8s9t0u1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CustomerUpdate"
      responses:
        "200":
          description: Updated customer
          headers:
            x-ratelimit-limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            x-ratelimit-remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            x-ratelimit-reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Customer"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          $ref: "#/components/responses/Conflict"
