Skip to main content

Overview

An EV charger’s maximum charging power is a ceiling the charger operates under, not a one-off command, so it is a device setting: max_charge_rate, in kw. Write it once and it persists across sessions until you change it or the charger reverts to its own defaults. Use it to balance against household consumption, throttle to a cheaper tariff window, or coordinate multiple chargers behind a single supply. The charger’s two commands stay clean intents. charge begins or resumes a session; idle pauses it, holding the session. The power cap survives both. Commands run through POST /ev-charger/{deviceId}; the setting runs through POST /ev-charger/{deviceId}/settings. See canonical actions on the actions-versus-settings boundary.
Coming soon. Live control for EV chargers. The sandbox environment serves the full commands and settings surface, so the walkthrough below works against a sandbox device today. A live EV charger push returns 422 COMMAND_NOT_SUPPORTED until the live path opens.

Step 1: Read the current state

Every response is wrapped in { success, data, meta }; the device sits under data.
curl -X GET https://api.amps.ai/ev-charger/device_ev_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "success": true,
  "data": {
    "id": "device_ev_001",
    "vendor": "example_vendor_a",
    "sync": { "available": true, "lastPulledAt": "2026-05-08T11:30:00.000Z" },
    "metadata": { "model": "7kW AC Charger", "source": "projection" },
    "state": {
      "status": "charging",
      "isConnected": true,
      "isCharging": true,
      "currentPower": 11,
      "maxCurrent": 48,
      "powerRateLimit": 7.4
    },
    "conflictStrategies": ["cancel_and_replace"],
    "commands": {
      "charge": { "parameters": {}, "execution": ["immediate", "scheduled", "windowed"] },
      "idle":   { "parameters": {}, "execution": ["immediate", "scheduled"] }
    },
    "settings": {
      "max_charge_rate": { "value": 11, "unit": "kw", "min": 0, "max": 50 }
    },
    "lastAction": null,
    "currentSchedule": null
  },
  "meta": {
    "requestId": "req_1uM5iVyL",
    "environment": "sandbox",
    "timestamp": "2026-05-08T11:30:00.000Z",
    "latencyMs": 33
  }
}
The charger is connected and drawing 11 kW. data.settings.max_charge_rate is the writable ceiling, bounded 0 to 50 kw. metadata.source reports where the reading came from. Sandbox device reads always carry source: "projection" because sandbox devices are simulated, not physical hardware. In live, the value is one of cache, live, or fallback, naming the data-freshness tier the read came back from.

Step 2: Cap the power

Write max_charge_rate through the settings endpoint. The body is a sparse map: send only the settings you want to change. The value is the canonical {value, unit} shape.
curl -X POST https://api.amps.ai/ev-charger/device_ev_001/settings \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "max_charge_rate": { "value": 7.4, "unit": "kw" }
  }'
Settings are fire-and-forget. The response acknowledges the write and echoes the keys that changed, under the standard data envelope.
{
  "success": true,
  "data": {
    "deviceId": "device_ev_001",
    "updated": ["max_charge_rate"]
  },
  "meta": {
    "requestId": "req_2vN6jWzM",
    "environment": "sandbox",
    "timestamp": "2026-05-08T11:31:14.000Z",
    "latencyMs": 71
  }
}
A value outside 0 to 50 returns 422 SETTING_OUT_OF_RANGE. An unknown key returns 422 UNSUPPORTED_SETTING; a read-only key returns 422 READ_ONLY_SETTING. The bounds come from the device read, so check data.settings on the GET before you write.

Step 3: Verify the cap applied

Read the device again. The new ceiling shows on data.settings, and live throughput settles to the cap.
{
  "success": true,
  "data": {
    "id": "device_ev_001",
    "vendor": "example_vendor_a",
    "sync": { "available": true, "lastPulledAt": "2026-05-08T11:32:02.000Z" },
    "metadata": { "model": "7kW AC Charger", "source": "projection" },
    "state": {
      "status": "charging",
      "isConnected": true,
      "isCharging": true,
      "currentPower": 7.4,
      "maxCurrent": 32,
      "powerRateLimit": 7.4
    },
    "conflictStrategies": ["cancel_and_replace"],
    "settings": {
      "max_charge_rate": { "value": 7.4, "unit": "kw", "min": 0, "max": 50 }
    },
    "lastAction": null,
    "currentSchedule": null
  },
  "meta": { "requestId": "req_3wO7kXaN", "environment": "sandbox", "timestamp": "2026-05-08T11:32:02.000Z", "latencyMs": 35 }
}

Start and stop a session

The cap is configuration; starting and stopping a session is intent. charge and idle are commands, sent in the canonical action envelope.
CommandUse
chargeBegin or resume a session on a connected vehicle.
idlePause the session, holding it.
Set the cap before starting a session to keep the first kWh inside a cheap rate, or change it mid-session as household demand spikes. The most recent setting wins.
curl -X POST https://api.amps.ai/ev-charger/device_ev_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "action": { "command": "charge" } }'
{
  "success": true,
  "data": {
    "id": "act_ev_007",
    "deviceId": "device_ev_001",
    "deviceType": "ev_charger",
    "command": "charge",
    "parameters": null,
    "state": "acknowledged",
    "createdAt": "2026-05-08T12:00:01.000Z",
    "links": { "self": "/actions/act_ev_007" }
  },
  "meta": { "requestId": "req_4xP8lYbO", "environment": "sandbox", "timestamp": "2026-05-08T12:00:01.000Z", "latencyMs": 92 }
}
This is an immediate push, so the action begins life in acknowledged rather than passing through scheduled. To pause without unplugging, push idle. Only one command is in flight at a time; submit a second while the first is acknowledged and you get 409 CONFLICT. Add onConflict: "cancel_and_replace" to drop the in-flight action and run the new one. EV chargers declare only cancel_and_replace, so queue_after returns 422 STRATEGY_NOT_SUPPORTED.

Why this works

The split between the max_charge_rate setting and the charge and idle commands is the actions-versus-settings boundary applied to a charger. A ceiling is persistent and non-conflicting, so it is a setting; starting a session is a time-bound intent, so it is a command. The same boundary puts a battery’s safety_reserve on settings and its charge on commands. See canonical actions and capabilities.

What next

Subscribe to webhooks

Get push.completed events on charger state changes.

Handle conflicts

Resolve 409s when a charger write is already in flight.

Hold an HVAC device

The mirrored command pattern on a thermostat.

Canonical actions

Where EV charger commands sit in the canonical model.