> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapa.energy/llms.txt
> Use this file to discover all available pages before exploring further.

# Charge the battery

> Charges the battery at the highest power the device allows, from on-site
production and, if `allow_import` is true, from the grid. Charging stops when
stored energy reaches `max_wh`, or at `end`.




## OpenAPI

````yaml /openapi.yaml post /bat/v1/{id}/charge
openapi: 3.1.0
info:
  title: Kapa Energy Battery API
  version: 1.0.0-draft.1
  summary: One API to control and monitor residential batteries across manufacturers.
  description: >
    The Kapa Energy Battery API gives HEMS and VPP operators a single interface
    to send

    commands to residential batteries and read their telemetry, whatever the

    manufacturer. Kapa translates each request into the manufacturer's own cloud
    API.


    ## Conventions


    ### Time

    - Timestamps are RFC 3339, in UTC, with a `Z` suffix:
    `2026-11-12T18:00:00Z`.

    - Durations are ISO 8601: `PT15M`.

    - Time windows are half-open, `[start, end)`: `start` is included, `end` is
    excluded.


    ### Power

    Power is in watts (W), as integers.

    - **Positive (+)**: the battery is discharging, or the site is exporting to
    the grid.

    - **Negative (−)**: the battery is charging, or the site is importing from
    the grid.


    Nominal ratings such as `nominal_charge_power_w` are magnitudes and are
    always positive.


    ### Energy

    Energy is in watt-hours (Wh), as integers. Battery levels are expressed as
    stored

    energy in Wh rather than state of charge in %, because the meaning of SoC
    differs

    between manufacturers. Stored energy is measured against the usable
    capacity: it

    ranges from 0 to `usable_capacity_wh`.


    ### Telemetry

    - Each data point carries two times: `measured_at`, when the device took the
      measurement, and `received_at`, when Kapa retrieved it from the manufacturer's cloud.
    - Data points are never interpolated or resampled. Each point is an actual
      measurement reported by the manufacturer. Units, signs and field names are
      standardised across manufacturers; a field the manufacturer does not report is `null`.

    ## Commands

    - Commands are asynchronous. Command endpoints return `202 Accepted` with a
    command
      whose `status` then evolves. Follow it with `GET /bat/v1/{id}/commands` or the
      `command.status_changed` webhook.
    - A `start` in the past is treated as the time Kapa accepts the command.

    - **Overlaps:** when a new command overlaps existing commands on the same
    battery,
      the newest command takes precedence over the overlapping period. Older commands
      stay in effect outside it. A command whose whole window is covered by newer
      commands becomes `superseded`.
    - Outside any command window, the battery follows its **default behaviour**:
    the
      mode its owner configured in the manufacturer's app.

    ## Idempotency

    Command and batch endpoints accept an optional `Idempotency-Key` header.
    Kapa stores

    the key with the response for 24 hours. A retry with the same key and the
    same body

    returns the original response without sending anything again.


    ## Errors

    Errors use RFC 9457 Problem Details (`application/problem+json`). The `code`
    field is

    stable and meant for programs; `title` and `detail` are meant for humans.


    | `code` | HTTP | Meaning |

    |---|---|---|

    | `invalid_parameters` | 400 | A parameter is missing, malformed or
    inconsistent (e.g. `min_wh` greater than `max_wh`). |

    | `invalid_time_window` | 400 | `start` is not before `end`, or `end` is in
    the past. |

    | `overlapping_operations` | 400 | Two operations of a batch target the same
    battery over overlapping windows. |

    | `unauthorized` | 401 | The access token is missing, invalid or expired. |

    | `battery_not_found` | 404 | No battery with this id is accessible to the
    client. |

    | `idempotency_key_in_use` | 409 | A request with the same `Idempotency-Key`
    is still being processed. |

    | `action_not_supported` | 422 | The battery cannot apply this command or
    parameter (e.g. `allow_import: false`). |

    | `energy_out_of_range` | 422 | An energy level exceeds the battery's usable
    capacity. |

    | `idempotency_key_reused` | 422 | The `Idempotency-Key` was already used
    with a different request body. |


    ## Webhooks

    Kapa pushes telemetry and command status changes to an HTTPS endpoint.
    Delivery is

    at least once and not ordered: deduplicate with `event_id`, and order data
    with

    `measured_at` or `updated_at`. Webhook registration is not covered by this
    version

    of the API.
servers:
  - url: https://api.kapa.energy
    description: Production
security:
  - oauth2: []
tags:
  - name: Authentication
    description: Obtain an OAuth 2.0 access token.
  - name: Batteries
    description: Static information about a battery.
  - name: Commands
    description: Control a single battery and follow the status of its commands.
  - name: Batches
    description: Send commands to many batteries in one request.
  - name: Telemetry
    description: Read measurements, standardised across manufacturers.
paths:
  /bat/v1/{id}/charge:
    parameters:
      - $ref: '#/components/parameters/BatteryId'
    post:
      tags:
        - Commands
      summary: Charge the battery
      description: >
        Charges the battery at the highest power the device allows, from on-site

        production and, if `allow_import` is true, from the grid. Charging stops
        when

        stored energy reaches `max_wh`, or at `end`.
      operationId: chargeBattery
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChargeRequest'
            example:
              start: '2026-11-12T13:00:00Z'
              end: '2026-11-12T15:00:00Z'
              allow_import: true
              max_wh: 12000
      responses:
        '202':
          description: Command accepted. Its status then evolves asynchronously.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
              example:
                command_id: cmd_501
                battery_id: bat_1
                action: charge
                parameters:
                  allow_import: true
                  max_wh: 12000
                start: '2026-11-12T13:00:00Z'
                end: '2026-11-12T15:00:00Z'
                status: pending
                status_reason: null
                batch_id: null
                created_at: '2026-11-12T12:41:07Z'
                updated_at: '2026-11-12T12:41:07Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
components:
  parameters:
    BatteryId:
      name: id
      in: path
      required: true
      description: Battery identifier.
      schema:
        type: string
      example: bat_1
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >
        Unique value identifying this request (a UUID is recommended). Reuse the
        same

        key and the same body when retrying. See Idempotency in the API
        description.
      schema:
        type: string
        maxLength: 255
      example: 7c1e4a90-5b2d-4f8e-9a31-0d6c2e8b1f47
  schemas:
    ChargeRequest:
      type: object
      allOf:
        - $ref: '#/components/schemas/OptionalWindow'
        - $ref: '#/components/schemas/ChargeParams'
      unevaluatedProperties: false
    Command:
      type: object
      required:
        - command_id
        - battery_id
        - action
        - parameters
        - start
        - end
        - status
        - status_reason
        - batch_id
        - created_at
        - updated_at
      properties:
        command_id:
          type: string
          description: Command identifier.
        battery_id:
          type: string
          description: Battery identifier.
        action:
          $ref: '#/components/schemas/Action'
        parameters:
          $ref: '#/components/schemas/CommandParameters'
        start:
          $ref: '#/components/schemas/Timestamp'
          description: >
            Effective start (inclusive). If the request omitted `start`, or gave
            a time

            in the past, this is the time Kapa accepted the command.
        end:
          $ref: '#/components/schemas/NullableTimestamp'
          description: >-
            End (exclusive). Null means open-ended, until cancelled or
            superseded.
        status:
          $ref: '#/components/schemas/CommandStatus'
        status_reason:
          type:
            - string
            - 'null'
          description: >
            Machine-readable reason when `status` is `failed`, e.g.
            `oem_rejected`,

            `oem_unreachable`, `battery_offline`. Null otherwise.
        batch_id:
          type:
            - string
            - 'null'
          description: >-
            Identifier of the batch that created the command. Null for single
            commands.
        created_at:
          $ref: '#/components/schemas/Timestamp'
          description: When Kapa accepted the command.
        updated_at:
          $ref: '#/components/schemas/Timestamp'
          description: Last status change.
    OptionalWindow:
      type: object
      properties:
        start:
          $ref: '#/components/schemas/NullableTimestamp'
          description: >-
            Start of the command (inclusive). Omitted or null means as soon as
            possible.
        end:
          $ref: '#/components/schemas/NullableTimestamp'
          description: >-
            End of the command (exclusive). Omitted or null means until
            cancelled or superseded.
    ChargeParams:
      type: object
      properties:
        allow_import:
          type: boolean
          default: true
          description: >
            If true, the battery may charge from the grid. If false, it only
            charges from

            on-site production (PV surplus).
        max_wh:
          type:
            - integer
            - 'null'
          minimum: 0
          description: >
            Stored energy level, in Wh, at which charging stops. Must not exceed

            `usable_capacity_wh`. Omitted or null means up to the full usable
            capacity.
    Action:
      type: string
      enum:
        - charge
        - discharge
        - autoconsume
        - idle
      description: |
        - `charge`: charge the battery.
        - `discharge`: discharge the battery.
        - `autoconsume`: self-consumption.
        - `idle`: neither charge nor discharge.
    CommandParameters:
      type: object
      description: >
        Action-specific parameters, as accepted. `charge` uses `allow_import`
        and

        `max_wh`; `discharge` and `autoconsume` use `min_wh` and `max_wh`;
        `idle` has none.
      properties:
        allow_import:
          type: boolean
        min_wh:
          type:
            - integer
            - 'null'
          minimum: 0
        max_wh:
          type:
            - integer
            - 'null'
          minimum: 0
      additionalProperties: false
    Timestamp:
      type: string
      format: date-time
      pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$
      description: RFC 3339 timestamp in UTC, with a `Z` suffix.
      examples:
        - '2026-11-12T18:00:00Z'
    NullableTimestamp:
      type:
        - string
        - 'null'
      format: date-time
      pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$
      description: RFC 3339 timestamp in UTC, with a `Z` suffix, or null.
    CommandStatus:
      type: string
      enum:
        - pending
        - scheduled
        - active
        - completed
        - cancelled
        - superseded
        - failed
      description: >
        - `pending`: accepted by Kapa, not yet acknowledged by the
        manufacturer's cloud.

        - `scheduled`: acknowledged by the manufacturer; `start` is in the
        future.

        - `active`: in effect on the battery.

        - `completed`: the window ended normally.

        - `cancelled`: cancelled with `cancel_command`.

        - `superseded`: the whole window is covered by more recent commands.

        - `failed`: the command could not be applied; see `status_reason`.
    Problem:
      type: object
      description: Error details, following RFC 9457 (Problem Details for HTTP APIs).
      required:
        - type
        - title
        - status
        - code
      properties:
        type:
          type: string
          format: uri-reference
          description: URI identifying the problem type.
        title:
          type: string
          description: Short, human-readable summary of the problem type.
        status:
          type: integer
          description: HTTP status code.
        code:
          type: string
          description: >-
            Stable, machine-readable error code. See Errors in the API
            description.
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
        invalid_params:
          type: array
          description: Parameters that caused the error, if any.
          items:
            type: object
            required:
              - name
              - reason
            properties:
              name:
                type: string
              reason:
                type: string
  responses:
    BadRequest:
      description: The request is malformed or its parameters are invalid.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.kapa.energy/problems/invalid-time-window
            title: Invalid time window
            status: 400
            code: invalid_time_window
            detail: end must be after start.
            invalid_params:
              - name: end
                reason: must be after start
    Unauthorized:
      description: The access token is missing, invalid or expired.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.kapa.energy/problems/unauthorized
            title: Unauthorized
            status: 401
            code: unauthorized
            detail: The access token has expired.
    NotFound:
      description: No battery with this id is accessible to the client.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.kapa.energy/problems/battery-not-found
            title: Battery not found
            status: 404
            code: battery_not_found
            detail: No battery with id bat_9 is accessible to this client.
    Conflict:
      description: A request with the same Idempotency-Key is still being processed.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.kapa.energy/problems/idempotency-key-in-use
            title: Idempotency key in use
            status: 409
            code: idempotency_key_in_use
            detail: Retry once the original request has completed.
    Unprocessable:
      description: >
        The request is valid but cannot be applied to this battery

        (`action_not_supported`, `energy_out_of_range`), or the Idempotency-Key
        was

        already used with a different body (`idempotency_key_reused`).
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          example:
            type: https://api.kapa.energy/problems/energy-out-of-range
            title: Energy out of range
            status: 422
            code: energy_out_of_range
            detail: >-
              max_wh (15000) exceeds the usable capacity of this battery (13000
              Wh).
            invalid_params:
              - name: max_wh
                reason: exceeds usable_capacity_wh
  securitySchemes:
    oauth2:
      type: oauth2
      description: OAuth 2.0 client credentials. Obtain a token from `POST /token`.
      flows:
        clientCredentials:
          tokenUrl: https://api.kapa.energy/token
          scopes: {}

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.