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

# Push battery action

> Send a command to a battery device. Immediate actions fire as soon as the platform dispatches them; deferred actions (with `start`) fire at the requested time. The action is processed asynchronously and a webhook is sent on completion.



## OpenAPI

````yaml /openapi.json post /battery/{deviceId}
openapi: 3.1.0
info:
  title: Amps.ai API
  description: >-
    Energy device management API for batteries, EV chargers, solar inverters,
    and HVAC systems
  version: '1.0'
  contact: {}
servers:
  - url: https://api.amps.ai
    description: Amps API
security: []
tags: []
paths:
  /battery/{deviceId}:
    post:
      tags:
        - Battery
      summary: Push battery action
      description: >-
        Send a command to a battery device. Immediate actions fire as soon as
        the platform dispatches them; deferred actions (with `start`) fire at
        the requested time. The action is processed asynchronously and a webhook
        is sent on completion.
      operationId: pushBattery
      parameters:
        - name: deviceId
          required: true
          in: path
          description: The unique identifier for the battery device.
          schema:
            example: device_abc123
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatteryPushRequest'
            examples:
              chargeImmediateTarget:
                summary: Charge immediately to a target SoC
                description: >-
                  Charge with concrete `target` cap. No `start` means immediate.
                  Parameters use the canonical `{ value, unit }` shape.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 80
                        unit: percent
              chargeImmediatePower:
                summary: Charge immediately with a power cap
                description: >-
                  Cap the charge rate at a specific kW value. Useful for trickle
                  charging or limiting grid draw during a peak.
                value:
                  action:
                    command: charge
                    parameters:
                      power:
                        value: 1.5
                        unit: kw
              chargeImmediateTargetAndPower:
                summary: Charge immediately with both `target` and `power` caps
                description: >-
                  Combine an upper SoC limit with a rate cap. The battery stops
                  at `target` or when external constraints intervene.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 95
                        unit: percent
                      power:
                        value: 3
                        unit: kw
              chargeWithReserve:
                summary: Charge while preserving a reserve floor
                description: >-
                  `reserve` acts as a second safety floor distinct from the
                  device-wide `discharge_floor` setting. Active only while the
                  mode is in effect.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 90
                        unit: percent
                      reserve:
                        value: 20
                        unit: percent
              chargeScheduled:
                summary: Charge starting at a future time (deferred)
                description: >-
                  `start` alone schedules the action to fire when the device's
                  clock reaches the given wall-clock. Returns 202 with `state:
                  scheduled`. The platform interprets `start` in the device's
                  plant timezone.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 100
                        unit: percent
                    start: '2026-06-01T02:00:00'
              chargeScheduledRelative:
                summary: Charge starting after a relative duration
                description: >-
                  `start` accepts relative durations (`30m`, `1.5h`, `2h`).
                  Resolved server-side at request time.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 100
                        unit: percent
                    start: 30m
              chargeWindowedPower:
                summary: Charge during a window with a rate cap
                description: >-
                  `start` + `end` together describe a windowed action. Available
                  on `charge`/`discharge` whose execution set includes
                  `windowed`. Both fields are plant-local wall-clock.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 100
                        unit: percent
                      power:
                        value: 3
                        unit: kw
                    start: '2026-06-01T02:00:00'
                    end: '2026-06-01T06:00:00'
              dischargeImmediateTarget:
                summary: Discharge immediately to a target SoC floor
                description: >-
                  For `discharge`, `target` is the lower SoC limit. The battery
                  stops discharging when it hits this level.
                value:
                  action:
                    command: discharge
                    parameters:
                      target:
                        value: 30
                        unit: percent
              dischargeImmediatePower:
                summary: Discharge immediately with a power cap
                description: >-
                  Cap the discharge rate. Useful when you want to leave headroom
                  for a sudden load spike.
                value:
                  action:
                    command: discharge
                    parameters:
                      power:
                        value: 2
                        unit: kw
              dischargeScheduled:
                summary: Discharge starting at a future time
                value:
                  action:
                    command: discharge
                    parameters:
                      target:
                        value: 30
                        unit: percent
                    start: '2026-05-08T17:00:00'
              dischargeWindowedPower:
                summary: Discharge during a peak-pricing window
                description: >-
                  Time-bounded discharge from `start` to `end`. After the
                  window, the device returns to its prior mode. Both fields are
                  plant-local wall-clock.
                value:
                  action:
                    command: discharge
                    parameters:
                      power:
                        value: 3
                        unit: kw
                    start: '2026-05-08T17:00:00'
                    end: '2026-05-08T20:00:00'
              idleImmediate:
                summary: Pause all activity immediately
                description: >-
                  No parameters. Stops both charge and discharge until a
                  follow-up command.
                value:
                  action:
                    command: idle
              idleScheduled:
                summary: Pause activity at a future time
                value:
                  action:
                    command: idle
                    start: '2026-05-08T22:00:00'
              autoBalancedImmediate:
                summary: Switch to auto.balance (no parameters)
                description: >-
                  Hand control back to the platform-managed self-consumption
                  strategy.
                value:
                  action:
                    command: auto.balance
              autoBalancedScheduled:
                summary: Switch to auto.balance at a future time
                value:
                  action:
                    command: auto.balance
                    start: '2026-05-08T08:00:00'
              autoReserveImmediate:
                summary: Reserve capacity for grid outage protection
                description: >-
                  Battery stays charged above the configured reserve floor.
                  Discharge only triggers below the reserve threshold.
                value:
                  action:
                    command: auto.reserve
              autoExportImmediate:
                summary: Maximise grid export when tariff is attractive
                description: >-
                  Discharge to grid whenever the export tariff justifies it.
                  Platform-driven; no parameters.
                value:
                  action:
                    command: auto.export
              chargeCancelAndReplace:
                summary: Cancel any conflicting action and apply this one
                description: >-
                  `cancel_and_replace` replaces a scheduled or windowed conflict
                  that has not been dispatched yet. A command already sent to
                  the manufacturer cannot be recalled, so it returns 409
                  `CONFLICT_IN_EXECUTION`. Without `onConflict`, a colliding
                  action returns 409.
                value:
                  action:
                    command: charge
                    parameters:
                      target:
                        value: 100
                        unit: percent
                  onConflict: cancel_and_replace
              chargeQueueAfter:
                summary: Queue this action behind any conflicting one
                description: >-
                  `queue_after` defers this action until the conflicting one
                  completes. The fire time is implicit, not user-specified.
                value:
                  action:
                    command: discharge
                  onConflict: queue_after
              sandboxFail:
                summary: Simulate a failure in sandbox
                description: >-
                  Sandbox-only. Use `sandbox.result: "failed"` plus an
                  `errorCode` to test client error handling without touching a
                  real device.
                value:
                  action:
                    command: charge
                  sandbox:
                    result: failed
                    errorCode: COMMAND_NOT_SUPPORTED
      responses:
        '202':
          description: >-
            Action accepted. For immediate actions, `state: acknowledged` means
            the command has been dispatched; for deferred actions, `state:
            scheduled` and `start` carries the fire time.
          content:
            application/json:
              schema:
                type: object
                required:
                  - success
                  - data
                  - meta
                properties:
                  success:
                    type: boolean
                    const: true
                    description: Always `true` for success responses.
                  data:
                    $ref: '#/components/schemas/BatteryPushResponse'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              examples:
                immediateAcknowledged:
                  summary: Immediate action dispatched
                  description: >-
                    The response mirrors the dispatch: `command` + `parameters`
                    + `deviceType`. `state: acknowledged` means the platform
                    dispatched the action. The platform runs it next; a webhook
                    fires when it reaches a terminal state. Track it at
                    `links.self`.
                  value:
                    success: true
                    data:
                      id: act_2026050710b3c4d5
                      deviceId: dev_b1a2c3d4e5
                      deviceType: battery
                      command: charge
                      parameters:
                        target:
                          value: 80
                          unit: percent
                      state: acknowledged
                      createdAt: '2026-05-07T10:00:00.000Z'
                      start: null
                      links:
                        self: /actions/act_2026050710b3c4d5
                    meta:
                      requestId: req_8a2Bf3kP
                      environment: sandbox
                      timestamp: '2026-06-02T12:00:00.000Z'
                      latencyMs: 12
                deferredScheduled:
                  summary: Deferred action scheduled to fire at `start`
                  description: >-
                    `state: scheduled` and `start` carries the absolute fire
                    time. Cancel via `POST /actions/{actionId}/cancel` before
                    then.
                  value:
                    success: true
                    data:
                      id: act_2026050709a1b2c3
                      deviceId: dev_b1a2c3d4e5
                      deviceType: battery
                      command: charge
                      parameters:
                        target:
                          value: 100
                          unit: percent
                      state: scheduled
                      createdAt: '2026-05-07T08:00:00.000Z'
                      start: '2026-06-01T02:00:00.000Z'
                      links:
                        self: /actions/act_2026050709a1b2c3
                    meta:
                      requestId: req_8a2Bf3kP
                      environment: sandbox
                      timestamp: '2026-06-02T12:00:00.000Z'
                      latencyMs: 12
                windowedScheduled:
                  summary: Windowed action scheduled (start + end)
                  description: >-
                    Windowed actions are a deferred shape: `start` carries the
                    begin time, `end` (returned on the action record itself) the
                    end. The push response surfaces only `start` because the
                    response shape is shared with non-windowed actions.
                  value:
                    success: true
                    data:
                      id: act_2026050708e5f6g7
                      deviceId: dev_b1a2c3d4e5
                      deviceType: battery
                      command: discharge
                      parameters:
                        power:
                          value: 3
                          unit: kw
                      state: scheduled
                      createdAt: '2026-05-07T07:30:00.000Z'
                      start: '2026-06-01T02:00:00.000Z'
                      links:
                        self: /actions/act_2026050708e5f6g7
                    meta:
                      requestId: req_8a2Bf3kP
                      environment: sandbox
                      timestamp: '2026-06-02T12:00:00.000Z'
                      latencyMs: 12
                queuedAfter:
                  summary: Action queued after an in-flight conflict
                  description: >-
                    When `onConflict: queue_after` is set, the action is
                    scheduled to fire after the conflicting one completes.
                    `start` may be null until the predecessor lands.
                  value:
                    success: true
                    data:
                      id: act_2026050711h8j9k0
                      deviceId: dev_b1a2c3d4e5
                      deviceType: battery
                      command: discharge
                      parameters: null
                      state: scheduled
                      createdAt: '2026-05-07T11:00:00.000Z'
                      start: null
                      links:
                        self: /actions/act_2026050711h8j9k0
                    meta:
                      requestId: req_8a2Bf3kP
                      environment: sandbox
                      timestamp: '2026-06-02T12:00:00.000Z'
                      latencyMs: 12
        '400':
          description: >-
            Invalid request body (failed Zod schema validation). The device
            manufacturer can also refuse a well-formed request with this status
            (`BIND_NOT_SUPPORTED`, `COMMAND_FAILED`, `INVALID_OEM_PARAMETERS`,
            `INVALID_PARAMETERS`, `UNSUPPORTED_AUTH_PATH`,
            `UNSUPPORTED_CREDENTIAL_TYPE`). Every code at this status:
            `BIND_NOT_SUPPORTED`, `COMMAND_FAILED`, `INVALID_OEM_PARAMETERS`,
            `INVALID_PARAMETERS`, `INVALID_REQUEST_BODY`,
            `UNSUPPORTED_AUTH_PATH`, `UNSUPPORTED_CREDENTIAL_TYPE`,
            `VALIDATION_ERROR`. See the [device error
            codes](/reference/error-codes) reference for the full set.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                commandNotSupported:
                  summary: >-
                    The manufacturer accepted the request but refused to run
                    this command on this device. See [device error
                    codes](/reference/error-codes).
                  value:
                    success: false
                    error:
                      code: COMMAND_NOT_SUPPORTED
                      message: The device manufacturer does not support this command.
                    meta:
                      requestId: req_9hH4nVeF
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 162
                missingAction:
                  summary: '`action` field missing from the body'
                  value:
                    success: false
                    error:
                      code: INVALID_REQUEST_BODY
                      message: The request body is invalid.
                      details:
                        fields:
                          action:
                            - Required
                        description: Invalid request body
                    meta:
                      requestId: req_1bA0eFgC
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 3
                missingCommand:
                  summary: >-
                    `action` is present but carries no `command`. A command the
                    platform does not recognise (`auto.balanced`) is NOT a 400 —
                    it is a 422 `UNSUPPORTED_MODE` naming the modes this battery
                    accepts, exactly like a canonical command from another
                    device family such as `heat`.
                  value:
                    success: false
                    error:
                      code: INVALID_REQUEST_BODY
                      message: The request body is invalid.
                      details:
                        fields:
                          action.command:
                            - >-
                              Unsupported command. This device supports:
                              `charge`, `discharge`, `idle`, `auto.balance`,
                              `auto.reserve`, `auto.export`.
                        description: Invalid request body
                    meta:
                      requestId: req_6mE3jKlW
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 3
                invalidStartFormat:
                  summary: '`start` is not wall-clock nor a relative duration'
                  value:
                    success: false
                    error:
                      code: INVALID_REQUEST_BODY
                      message: The request body is invalid.
                      details:
                        fields:
                          action.start:
                            - >-
                              start must be ISO 8601 with timezone (e.g.
                              `2026-06-01T02:00:00Z`) or a relative duration
                              (e.g. `30m`).
                        description: Invalid request body
                    meta:
                      requestId: req_2cD4gMnY
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 4
                startCarriesOffset:
                  summary: '`start` carries a `Z` or `+HH:MM` offset'
                  value:
                    success: false
                    error:
                      code: INVALID_REQUEST_BODY
                      message: The request body is invalid.
                      details:
                        action.start:
                          - >-
                            start must be plant-local wall-clock without an
                            offset. Times are plant-local wall-clock. Drop the
                            `Z` / `+HH:MM` suffix and submit
                            `YYYY-MM-DDTHH:MM:SS` (e.g. `2026-06-01T22:00:00`).
                        description: Invalid request body
                    meta:
                      requestId: req_4eF6iOpA
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 4
                endBeforeStart:
                  summary: '`end` is before `start`'
                  value:
                    success: false
                    error:
                      code: INVALID_REQUEST_BODY
                      message: The request body is invalid.
                      details:
                        fields:
                          action.end:
                            - end must be after start
                        description: Invalid request body
                    meta:
                      requestId: req_3dE5hNoZ
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 4
        '401':
          description: Invalid or missing API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingApiKey:
                  summary: No `x-api-key` header present
                  value:
                    success: false
                    error:
                      code: UNAUTHORIZED
                      message: Authentication is required.
                      details:
                        description: API key is required
                    meta:
                      requestId: req_8sW2dRtX
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 2
        '403':
          description: >-
            Error codes: `FORBIDDEN`, `INVALID_MFA_CODE`, `MFA_REQUIRED`,
            `ACCOUNT_LOCKED`, `DEVICE_UNAUTHORIZED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Device not found or access denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                deviceNotFound:
                  summary: No device matches the ID for this customer
                  value:
                    success: false
                    error:
                      code: DEVICE_NOT_FOUND
                      message: No matching device was found for the supplied details.
                      details:
                        description: Device not found or access denied
                    meta:
                      requestId: req_5pH1cQbY
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_unknown_999
                      latencyMs: 5
        '409':
          description: >-
            A conflicting action is already in progress, or the device has a
            schedule the request conflicts with. Codes: `CONFLICT`,
            `CONFLICT_IN_EXECUTION`, `SCHEDULER_ACTIVE`, `SCHEDULER_FULL`,
            `MODE_OVERRIDDEN`, `VPP_LOCKED`. Provide `onConflict:
            "cancel_and_replace"` or `"queue_after"` to resolve Amps-tracked
            conflicts; resolve device-side conflicts via the strategies in
            `details.recoveryStrategies`. See [conflict
            resolution](/concepts/conflict-resolution). Every code at this
            status: `CONFLICT`, `CONFLICT_IN_EXECUTION`, `MODE_OVERRIDDEN`,
            `SCHEDULER_ACTIVE`, `SCHEDULER_FULL`, `VPP_LOCKED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                conflictNoStrategy:
                  summary: Caller did not provide an `onConflict` strategy
                  value:
                    success: false
                    error:
                      code: CONFLICT
                      message: The request conflicts with the current resource state.
                      details:
                        reason: no_strategy_supplied
                        conflictingActionIds:
                          - act_2026050709a1b2c3
                        strategies:
                          - cancel_and_replace
                          - queue_after
                        description: >-
                          A conflicting action is already pending for this
                          device. Provide onConflict to resolve automatically,
                          or cancel the existing action.
                    meta:
                      requestId: req_2cB5gNqR
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 14
                conflictInFlight:
                  summary: >-
                    `cancel_and_replace` requested but the conflicting action is
                    already acknowledged
                  value:
                    success: false
                    error:
                      code: CONFLICT_IN_EXECUTION
                      message: A conflicting action is already being executed.
                      details:
                        reason: conflicting_action_in_progress
                        conflictingActionIds:
                          - act_2026050710b3c4d5
                        description: >-
                          The conflicting action is already in progress and
                          cannot be cancelled. Wait for it to complete or fail.
                    meta:
                      requestId: req_3dC6hOsT
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 18
                conflictWithCapReached:
                  summary: Per-device queue depth limit hit
                  value:
                    success: false
                    error:
                      code: CONFLICT
                      message: The request conflicts with the current resource state.
                      details:
                        conflictingActionIds:
                          - act_2026050709a1b2c3
                          - act_2026050708e5f6g7
                        queueDepth: 2
                        queueLimit: 2
                        description: >-
                          Device queue is full. Cancel a queued action before
                          pushing a new one.
                    meta:
                      requestId: req_4eD7iPtU
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 16
                schedulerActive:
                  summary: >-
                    A schedule the device already holds (foreign or stale)
                    overlaps the requested window. Resubmit with `onConflict:
                    cancel_and_replace` to merge.
                  value:
                    success: false
                    error:
                      code: SCHEDULER_ACTIVE
                      message: >-
                        A schedule is currently active on the device and must be
                        cleared first.
                      details:
                        reason: foreign_scheduler_window_overlap
                        description: >-
                          A schedule not created by Amps (homeowner app,
                          external automation, or a previously-set Amps schedule
                          whose action is terminal) overlaps this windowed
                          write.
                        existingGroupCount: 2
                        overlappingGroups:
                          - workMode: charge
                            startHour: 0
                            startMinute: 0
                            endHour: 6
                            endMinute: 0
                        recoveryStrategies:
                          - cancel_and_replace
                          - manual_clear_via_device_app
                        detectedAt: submission_time
                    meta:
                      requestId: req_AkK3oVbB
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 12
        '410':
          description: >-
            The device is offline at the manufacturer (`DEVICE_OFFLINE`).
            Transient; retry once the device is back online.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                deviceOffline:
                  summary: >-
                    The manufacturer reports the device as offline. Transient:
                    retry once the device is back online.
                  value:
                    success: false
                    error:
                      code: DEVICE_OFFLINE
                      message: The device is currently offline at the manufacturer.
                    meta:
                      requestId: req_BjL3pWcD
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 184
        '413':
          description: 'Error codes: `PAYLOAD_TOO_LARGE`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '415':
          description: 'Error codes: `UNSUPPORTED_MEDIA_TYPE`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: >-
            The request is well-formed but violates a device or canonical
            constraint. Common codes: `UNSUPPORTED_MODE`,
            `UNSUPPORTED_PARAMETER`, `EXECUTION_NOT_SUPPORTED`,
            `INVALID_TIME_WINDOW`, `DIRECT_ACTION_UNSUPPORTED`. The error
            `details` carries the offending values and the device capability
            subset. Every code at this status: `COMMAND_NOT_SUPPORTED`,
            `DIRECT_ACTION_UNSUPPORTED`, `EXECUTION_NOT_SUPPORTED`,
            `INVALID_TIMEZONE`, `INVALID_TIME_WINDOW`, `PARAMETER_OUT_OF_RANGE`,
            `SETTING_OUT_OF_RANGE`, `START_INVALID_FORMAT`, `START_IN_PAST`,
            `START_NONEXISTENT_WALL_CLOCK`, `START_OFFSET_NOT_ACCEPTED`,
            `START_OUT_OF_RANGE`, `STRATEGY_NOT_SUPPORTED`,
            `TIMEZONE_UNRESOLVED`, `UNSUPPORTED_ACTION`, `UNSUPPORTED_MODE`,
            `UNSUPPORTED_PARAMETER`, `UNSUPPORTED_PARAMETER_COMBINATION`,
            `UNSUPPORTED_UNIT`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                unsupportedMode:
                  summary: >-
                    The device doesn't support the requested mode. A non-battery
                    canonical command such as `heat` lands here too
                    (well-formed, so 422 not 400).
                  value:
                    success: false
                    error:
                      code: UNSUPPORTED_MODE
                      message: The requested mode is not supported by this device.
                      details:
                        deviceCapabilities:
                          supportedModes:
                            - charge
                            - discharge
                            - idle
                            - auto.balance
                            - auto.reserve
                        description: Mode `auto.export` is not supported by this device.
                    meta:
                      requestId: req_4eD7iPuU
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 9
                executionNotSupported:
                  summary: >-
                    Caller requested `windowed` on a mode that only supports
                    `immediate` and `scheduled`
                  value:
                    success: false
                    error:
                      code: EXECUTION_NOT_SUPPORTED
                      message: >-
                        The requested execution mode is not supported for this
                        device.
                      details:
                        requestedExecution: windowed
                        supportedExecution:
                          - immediate
                          - scheduled
                        description: >-
                          Mode 'auto.balance' does not support windowed
                          execution on this device. Supported shapes: immediate,
                          scheduled.
                    meta:
                      requestId: req_5fE8jQvV
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 8
                invalidTimeWindow:
                  summary: '`end` is not after `start`'
                  value:
                    success: false
                    error:
                      code: INVALID_TIME_WINDOW
                      message: The requested time window is invalid.
                      details:
                        description: end must be after start.
                    meta:
                      requestId: req_6gF9kRwW
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 5
                directActionUnsupported:
                  summary: Device only accepts native scheduling
                  value:
                    success: false
                    error:
                      code: DIRECT_ACTION_UNSUPPORTED
                      message: This device does not support imperative push commands.
                      details:
                        description: >-
                          This device does not support imperative push commands.
                          Use /schedules instead.
                    meta:
                      requestId: req_7hG0lSxX
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 6
                unsupportedParameter:
                  summary: >-
                    Caller supplied a parameter not accepted by this command.
                    The 422 names the offender and the supported set for this
                    mode.
                  value:
                    success: false
                    error:
                      code: UNSUPPORTED_PARAMETER
                      message: One or more parameters are not supported by this device.
                      details:
                        unsupportedParameters:
                          - target
                        deviceCapabilities:
                          supportedParameters: []
                        description: >-
                          Parameter(s) not supported for mode `auto.balance`:
                          target.
                    meta:
                      requestId: req_8iH1mTyZ
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 7
                unsupportedUnit:
                  summary: >-
                    `target` was sent in `kwh` but the canonical unit is
                    `percent`. `details` names the provided and supported units.
                  value:
                    success: false
                    error:
                      code: UNSUPPORTED_UNIT
                      message: A supplied parameter unit is not supported.
                      details:
                        parameter: target
                        providedUnit: kwh
                        supportedUnits:
                          - percent
                        description: >-
                          Parameter `target` unit `kwh` is not supported.
                          Expected `percent`.
                    meta:
                      requestId: req_9jJ2nUaA
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 6
                parameterOutOfRange:
                  summary: >-
                    `target` value exceeds the device-declared maximum.
                    `details` carries the bounds so the caller can correct
                    without a second GET.
                  value:
                    success: false
                    error:
                      code: PARAMETER_OUT_OF_RANGE
                      message: One or more parameters are outside the supported range.
                      details:
                        parameter: target
                        value: 150
                        min: 0
                        max: 100
                        unit: percent
                        description: Parameter `target` value 150 exceeds the maximum 100.
                    meta:
                      requestId: req_AjK2nUbB
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 6
        '429':
          description: >-
            The device manufacturer is rate limiting requests (`RATE_LIMITED`).
            Back off and retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                rateLimited:
                  summary: >-
                    The manufacturer hit a per-account or per-device limit. Back
                    off and retry.
                  value:
                    success: false
                    error:
                      code: RATE_LIMITED
                      message: >-
                        The device manufacturer is rate limiting requests.
                        Please try again shortly.
                    meta:
                      requestId: req_CkM4qXdE
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 96
        '500':
          description: 'Error codes: `INTERNAL_ERROR`, `UNKNOWN_ERROR`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '502':
          description: 'Error codes: `NETWORK_ERROR`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: >-
            The device manufacturer service is temporarily unavailable
            (`SERVICE_UNAVAILABLE`), or a sandbox-simulated failure
            (`SIMULATED_FAILURE`). Retryable with exponential backoff. See the
            [device error codes](/reference/error-codes) reference. Every code
            at this status: `NOT_YET_AVAILABLE`, `OEM_CIRCUIT_OPEN`,
            `SERVICE_UNAVAILABLE`, `SETTINGS_STORE_UNAVAILABLE`,
            `SIMULATED_FAILURE`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                serviceUnavailable:
                  summary: >-
                    The manufacturer cloud is down or refusing requests. Retry
                    with backoff.
                  value:
                    success: false
                    error:
                      code: SERVICE_UNAVAILABLE
                      message: >-
                        The device manufacturer service is temporarily
                        unavailable.
                    meta:
                      requestId: req_DlN5rYeF
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 2034
                simulatedFailure:
                  summary: >-
                    Sandbox-only: surfaced when `sandbox.result: "failed"` is
                    supplied to exercise error handling without touching a real
                    device.
                  value:
                    success: false
                    error:
                      code: SIMULATED_FAILURE
                      message: Simulated failure (sandbox).
                    meta:
                      requestId: req_EmO6sZgG
                      timestamp: '2026-04-29T12:00:00.000Z'
                      path: /battery/device_abc123
                      latencyMs: 12
        '504':
          description: 'Error codes: `TIMEOUT`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - api-key: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: |-
            curl --request POST \
              --url 'https://api.amps.ai/battery/device_abc123' \
              --header 'x-api-key: amps_sk_test_xxxxxxxxxxxxxxxxxxxxxxxx' \
              --header 'content-type: application/json' \
              --data '{
                "action": {
                  "command": "charge",
                  "parameters": {
                    "target": {
                      "value": 80,
                      "unit": "percent"
                    }
                  }
                }
              }'
        - lang: javascript
          label: Node
          source: >-
            const response = await
            fetch('https://api.amps.ai/battery/device_abc123', {
              method: 'POST',
              headers: {
                'x-api-key': 'amps_sk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
                'content-type': 'application/json',
              },
              body: JSON.stringify({
                "action": {
                  "command": "charge",
                  "parameters": {
                    "target": {
                      "value": 80,
                      "unit": "percent"
                    }
                  }
                }
              }),
            });


            const data = await response.json();
        - lang: python
          label: Python
          source: |-
            import requests

            url = 'https://api.amps.ai/battery/device_abc123'
            headers = {
                'x-api-key': 'amps_sk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
                'content-type': 'application/json',
            }
            payload = {
                "action": {
                    "command": "charge",
                    "parameters": {
                        "target": {
                            "value": 80,
                            "unit": "percent",
                        },
                    },
                },
            }

            response = requests.post(url, headers=headers, json=payload)
            data = response.json()
components:
  schemas:
    BatteryPushRequest:
      type: object
      properties:
        action:
          $ref: '#/components/schemas/BatteryAction'
        onConflict:
          $ref: '#/components/schemas/BatteryOnConflict'
        sandbox:
          $ref: '#/components/schemas/BatterySandboxConfig'
      required:
        - action
      description: >-
        A single battery action plus optional `onConflict` strategy and
        `sandbox` controls.


        Action variants describe what the API accepts. Per-device support
        varies; the `commands` map on `GET /battery/{deviceId}` shows which
        actions a specific device handles.
      examples:
        - action:
            command: charge
            parameters:
              target:
                value: 80
                unit: percent
              power:
                value: 3
                unit: kw
        - action:
            command: discharge
            start: '2026-05-08T17:00:00'
            end: '2026-05-08T20:00:00'
            parameters:
              target:
                value: 20
                unit: percent
          onConflict: cancel_and_replace
        - action:
            command: auto.balance
      title: Battery Push
    BatteryPushResponse:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the action.
          example: act_abc123xyz
        deviceId:
          type: string
          description: Device the action targets.
          example: dev_abc123xyz
        deviceType:
          type: string
          const: battery
          description: The device family the action targets.
        command:
          type: string
          enum:
            - charge
            - discharge
            - idle
            - auto.balance
            - auto.reserve
            - auto.export
          description: The canonical command issued. Mirrors the verb sent on dispatch.
        parameters:
          anyOf:
            - type: object
              properties:
                target:
                  $ref: '#/components/schemas/Quantity'
                power:
                  $ref: '#/components/schemas/Quantity'
                reserve:
                  $ref: '#/components/schemas/Quantity'
            - type: 'null'
          description: >-
            Constraints the command was issued with
            (`target`/`power`/`reserve`). Null for `idle` and the `auto.*`
            modes.
        state:
          type: string
          enum:
            - acknowledged
            - completed
            - failed
            - scheduled
            - cancelled
          description: >-
            Current state of the action. `scheduled` indicates a deferred action
            awaiting its fire time. `cancelled` is a terminal state reachable
            from `scheduled` via POST /actions/{actionId}/cancel.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when the action was created.
        start:
          description: >-
            Absolute firing instant for deferred actions, as an ISO 8601
            timestamp. Null or absent for immediate actions.
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
        end:
          description: >-
            Absolute end instant for windowed actions, as an ISO 8601 timestamp.
            Present whenever `end` was requested, including a window sent
            without a `start`, which runs from now until this instant. Null or
            absent when no `end` was requested.
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
        links:
          type: object
          properties:
            self:
              type: string
              description: >-
                Canonical path to this action: `GET /actions/{actionId}`. Poll
                it to follow the action to a terminal state.
          required:
            - self
          description: Hypermedia links for this action.
        warnings:
          description: >-
            Conditions observed at submission that delay the command taking
            effect. The command is accepted; each entry names what must clear
            first. Advisory and best-effort: absence means nothing to report,
            not a guarantee that nothing is blocking. Never sent for deferred
            pushes (the state now does not describe the fire time).
          type: array
          items:
            $ref: '#/components/schemas/PushWarning'
      required:
        - id
        - deviceId
        - deviceType
        - command
        - parameters
        - state
        - createdAt
        - links
      title: Battery Push Response
      description: >-
        Result of a push. Mirrors the dispatch (`command` + `parameters` +
        `deviceType`) and carries `links.self` to track the action. For
        immediate actions, `state` reflects the dispatch outcome. For deferred
        actions, `state` is `scheduled`, `start` carries the fire time, and
        `end` the window close when a window was requested.
    ResponseMeta:
      type: object
      title: Response Meta
      description: >-
        Metadata attached to every response: the request identifier, the serving
        environment, the build timestamp, and the server-side latency.
      required:
        - environment
        - timestamp
        - latencyMs
      properties:
        requestId:
          description: >-
            Unique request identifier. Echoes the `x-request-id` header when
            present; otherwise generated server-side.
          type: string
        environment:
          type: string
          description: The environment that served the request (`sandbox` or `live`).
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the response was built.
        latencyMs:
          type: integer
          description: Server-side processing time in milliseconds.
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Always `false` for error responses.
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - INVALID_CREDENTIALS
                - INVALID_API_KEY
                - INVALID_MFA_CODE
                - MFA_REQUIRED
                - ACCOUNT_LOCKED
                - UNSUPPORTED_CREDENTIAL_TYPE
                - DEVICE_NOT_FOUND
                - DEVICE_OFFLINE
                - DEVICE_UNAUTHORIZED
                - NO_DEVICES_FOUND
                - COMMAND_FAILED
                - COMMAND_NOT_SUPPORTED
                - EXECUTION_NOT_SUPPORTED
                - MODE_OVERRIDDEN
                - VPP_LOCKED
                - INVALID_PARAMETERS
                - INVALID_OEM_PARAMETERS
                - INVALID_TIME_WINDOW
                - BIND_NOT_SUPPORTED
                - SCHEDULER_ACTIVE
                - SCHEDULER_FULL
                - UNSUPPORTED_AUTH_PATH
                - SETTING_OUT_OF_RANGE
                - NETWORK_ERROR
                - RATE_LIMITED
                - SERVICE_UNAVAILABLE
                - TIMEOUT
                - NOT_YET_AVAILABLE
                - SIMULATED_FAILURE
                - UNKNOWN_ERROR
                - VEHICLE_NOT_CONNECTED
                - SESSIONS_NOT_SUPPORTED
                - CREDENTIAL_NOT_FOUND
                - OEM_CIRCUIT_OPEN
                - INVALID_OEM_RESPONSE
                - COMMAND_NOT_APPLIED
                - STALE_ACTION
                - DEFERRED_SCHEDULE_FAILED
                - UNROUTABLE_ACTION_TYPE
                - UNAUTHORIZED
                - EXPIRED_TOKEN
                - FORBIDDEN
                - INSUFFICIENT_PERMISSIONS
                - LIVE_ACCESS_DISABLED
                - VALIDATION_ERROR
                - INVALID_INPUT
                - INVALID_REQUEST_BODY
                - EMPTY_SETTINGS
                - PAYLOAD_TOO_LARGE
                - UNSUPPORTED_MEDIA_TYPE
                - NOT_FOUND
                - METHOD_NOT_ALLOWED
                - CONFLICT
                - CONFLICT_IN_EXECUTION
                - GONE
                - RATE_LIMIT_EXCEEDED
                - INTERNAL_ERROR
                - NOT_IMPLEMENTED
                - BAD_GATEWAY
                - GATEWAY_TIMEOUT
                - DEVICE_TYPE_MISMATCH
                - CONSENT_REVOKED
                - DEVICE_OVERAGE
                - SETTINGS_STORE_UNAVAILABLE
                - ACTION_NOT_FOUND
                - DIRECT_ACTION_UNSUPPORTED
                - UNSUPPORTED_ACTION
                - UNSUPPORTED_MODE
                - UNSUPPORTED_PARAMETER
                - UNSUPPORTED_PARAMETER_COMBINATION
                - UNSUPPORTED_UNIT
                - PARAMETER_OUT_OF_RANGE
                - START_IN_PAST
                - START_OUT_OF_RANGE
                - START_OFFSET_NOT_ACCEPTED
                - START_INVALID_FORMAT
                - START_NONEXISTENT_WALL_CLOCK
                - TIMEZONE_UNRESOLVED
                - INVALID_TIMEZONE
                - ACTION_NOT_CANCELLABLE
                - STRATEGY_NOT_SUPPORTED
                - UNSUPPORTED_SETTING
                - UNSUPPORTED_SETTING_COMBINATION
                - READ_ONLY_SETTING
                - INVALID_SETTING_UNIT
                - INVALID_SETTING_VALUE
                - NO_OP
                - NO_OVERRIDE
                - AVAILABILITY_ENV_UNSUPPORTED
                - UNSUPPORTED_COMBINATION
              description: >-
                Machine-readable error code (e.g. `VALIDATION_ERROR`,
                `CONFLICT`, `UNSUPPORTED_MODE`). Stable across releases; safe to
                switch on.
            message:
              type: string
              description: Human-readable error message.
            details:
              description: >-
                Structured context for the error: which fields were invalid,
                which actions conflicted, which capabilities the device
                declares. Shape varies by error code.
              type: object
              properties: {}
              additionalProperties: {}
          required:
            - code
            - message
          description: Error envelope.
        meta:
          type: object
          properties:
            requestId:
              description: >-
                Unique request identifier. Echoes the `x-request-id` header when
                present; otherwise generated server-side.
              type: string
            timestamp:
              type: string
              description: ISO 8601 timestamp when the error response was built.
            path:
              type: string
              description: Request path that produced the error.
            latencyMs:
              type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
              description: Server-side processing time in milliseconds.
          required:
            - timestamp
            - path
            - latencyMs
          description: Request metadata.
      required:
        - success
        - error
        - meta
      title: Error Response
      description: >-
        Uniform error response. The `error.code` identifies the failure,
        `error.message` carries a human-readable explanation, and
        `error.details` carries structured context (failed fields, conflicting
        action IDs, supported capabilities) where relevant.
    BatteryAction:
      type: object
      properties:
        command:
          type: string
          enum:
            - charge
            - discharge
            - idle
            - auto.balance
            - auto.reserve
            - auto.export
          description: >-
            The battery command. Device support varies; an unavailable battery
            command is rejected at runtime with `422 UNSUPPORTED_MODE` carrying
            the supported modes.
        parameters:
          $ref: '#/components/schemas/BatteryCommandParameters'
        start:
          description: >-
            Start time. Plant-local wall-clock ISO 8601 without timezone offset
            (e.g. `2026-06-01T22:00:00`), or a relative duration (e.g. `30m`,
            `1.5h`). The platform interprets the wall-clock in the device's
            plant timezone. Omit for immediate execution.
          type: string
        end:
          description: >-
            End time for windowed execution. Plant-local wall-clock ISO 8601
            without timezone offset (e.g. `2026-06-01T06:00:00`). Supplied
            without `start`, the window opens now: the command is sent on this
            request and confirmed in the response, which reports `state:
            acknowledged`, no `start`, and this `end`. The platform takes the
            command back when `end` arrives.
          type: string
      required:
        - command
      additionalProperties: false
      title: Battery Action
      description: >-
        A canonical battery command. `charge`/`discharge` move energy to/from
        the battery (bounded by `target`, rate-capped by `power`); `idle`
        pauses; the `auto.*` modes declare an optimisation intent.
      examples:
        - command: charge
          parameters:
            target:
              value: 90
              unit: percent
            power:
              value: 5
              unit: kw
        - command: charge
          start: '2026-05-08T22:00:00'
          parameters:
            target:
              value: 100
              unit: percent
        - command: discharge
          start: '2026-05-08T17:00:00'
          end: '2026-05-08T20:00:00'
          parameters:
            target:
              value: 30
              unit: percent
        - command: auto.balance
    BatteryOnConflict:
      type: string
      enum:
        - cancel_and_replace
        - queue_after
      description: >-
        `cancel_and_replace` cancels the active action before running this one;
        `queue_after` defers this one until the active action completes. Omit to
        receive 409 on conflict.
      title: Battery On Conflict
    BatterySandboxConfig:
      type: object
      properties:
        result:
          description: Outcome to simulate. Defaults to `success`.
          type: string
          enum:
            - success
            - failed
        errorCode:
          description: >-
            Error code to emit when `result` is `failed`. Defaults to
            `SIMULATED_FAILURE`. Constrained to the battery canonical error
            codes.
          type: string
          enum:
            - INVALID_CREDENTIALS
            - INVALID_API_KEY
            - INVALID_MFA_CODE
            - MFA_REQUIRED
            - ACCOUNT_LOCKED
            - UNSUPPORTED_CREDENTIAL_TYPE
            - DEVICE_NOT_FOUND
            - DEVICE_OFFLINE
            - DEVICE_UNAUTHORIZED
            - NO_DEVICES_FOUND
            - COMMAND_FAILED
            - COMMAND_NOT_SUPPORTED
            - EXECUTION_NOT_SUPPORTED
            - MODE_OVERRIDDEN
            - VPP_LOCKED
            - INVALID_PARAMETERS
            - INVALID_OEM_PARAMETERS
            - INVALID_TIME_WINDOW
            - BIND_NOT_SUPPORTED
            - SCHEDULER_ACTIVE
            - SCHEDULER_FULL
            - UNSUPPORTED_AUTH_PATH
            - SETTING_OUT_OF_RANGE
            - NETWORK_ERROR
            - RATE_LIMITED
            - SERVICE_UNAVAILABLE
            - TIMEOUT
            - NOT_YET_AVAILABLE
            - SIMULATED_FAILURE
            - UNKNOWN_ERROR
        oemError:
          description: >-
            Inject a raw device-manufacturer error (message, optional code and
            HTTP status) and receive back the canonical error code the platform
            classifies it to, exactly as a live failure would surface. Takes
            precedence over `errorCode` when `result` is `failed`.
          type: object
          properties:
            message:
              type: string
              minLength: 1
              maxLength: 4096
            oemCode:
              anyOf:
                - type: string
                - type: integer
                  minimum: -9007199254740991
                  maximum: 9007199254740991
            httpStatus:
              type: integer
              minimum: 100
              maximum: 599
          required:
            - message
          additionalProperties: false
      description: Sandbox controls for testing error paths. Ignored in live environments.
      title: Battery Sandbox Config
    Quantity:
      type: object
      properties:
        value:
          type: number
          description: Numeric magnitude.
        unit:
          type: string
          enum:
            - percent
            - kw
            - watts
            - kwh
            - amps
            - volts
            - hours
            - minutes
            - celsius
            - fahrenheit
          description: >-
            Unit of measure. Closed set so consumers can switch exhaustively at
            the type layer.
      required:
        - value
        - unit
      title: Quantity
      description: >-
        Self-describing numeric value with its unit. `value` is the magnitude,
        `unit` names one of the canonical units.
    PushWarning:
      type: object
      properties:
        code:
          type: string
          enum:
            - vehicle_not_connected
            - awaiting_authorization
          description: >-
            Stable identifier for the observed condition.
            `vehicle_not_connected`: no vehicle is plugged in.
            `awaiting_authorization`: the charge waits for approval in the
            manufacturer app.
        message:
          type: string
          description: Human-readable description of the condition.
        observedAt:
          type: string
          format: date-time
          description: >-
            When the reading behind this warning was taken, as an ISO 8601
            timestamp. A stale reading may no longer describe the device.
      required:
        - code
        - message
        - observedAt
      description: >-
        A condition observed at submission that delays the command taking
        effect. The command is accepted and armed; the warning names what must
        clear first. Never a refusal.
      title: Push Warning
    BatteryCommandParameters:
      type: object
      properties:
        target:
          $ref: '#/components/schemas/Quantity'
          description: >-
            State-of-charge limit. `charge` stops at this upper bound;
            `discharge` stops at this lower bound. (unit: `percent`, min: 0,
            max: 100)
        power:
          $ref: '#/components/schemas/Quantity'
          description: >-
            Rate cap. The battery will not charge/discharge faster than this
            rate. (unit: `kw`, min: 0, max: 1000)
        reserve:
          $ref: '#/components/schemas/Quantity'
          description: >-
            Reserve floor preserved while the mode is active. Acts as a second
            safety boundary distinct from the device-wide settings. (unit:
            `percent`, min: 0, max: 100)
      additionalProperties: {}
      description: >-
        Command parameters. `charge`/`discharge` accept `target`, `power`, and
        `reserve`; `idle` and the `auto.*` modes accept none. A parameter the
        command does not accept is rejected at runtime with `422
        UNSUPPORTED_PARAMETER`.
      title: Battery Command Parameters
  securitySchemes:
    api-key:
      type: apiKey
      in: header
      name: x-api-key

````