> ## 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.

# Cap Charging for a Grid Event

> Hold an EV charger under a grid operator's power limit for the length of an event, then restore the ceiling you saved.

## Overview

A grid operator can limit the power a home draws during a local overload. In Germany, §14a EnWG lets the operator reduce a controlled device to 4.2 kW until the event ends. The pattern is cap and restore. Lower the ceiling at the start of the event, and restore it at the end.

**Use the setting, not a command.** `max_charge_rate` is a standing ceiling. It bounds the session in progress, and it bounds any session that starts later inside the event window. A `charge` command also carries a `power` parameter, but that caps one session only. A `charge` command on an idle charger starts a session. A cap must never start a session, so the setting is the correct tool here. For the whole settings surface, see [cap an EV charger's power](/guides/cookbook/ev-charger-set-power).

**You hold the timer.** Amps stores no event schedule and no memory of the value before the cap. Save the current ceiling in your own store at the start of the event. Write it again at the end.

<Callout icon="clock" color="#ED6D2C">
  **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 503 `NOT_YET_AVAILABLE` until the live path opens.
</Callout>

## Step 1: Save the current ceiling

Read the device. Settings arrive on the device read, under `data.settings`. There is no separate settings read.

```bash theme={null}
curl -X GET https://api.amps.ai/ev-charger/device_ev_001 \
  -H "x-api-key: sk_test_xxxxxxxxxxxxxxxxxxxxxxxx"
```

```json theme={null}
{
  "success": true,
  "data": {
    "id": "device_ev_001",
    "vendor": "example_vendor_a",
    "sync": { "available": true, "lastPulledAt": "2026-08-12T17:58:00.000Z" },
    "metadata": { "model": "11kW AC Charger", "source": "projection" },
    "state": {
      "status": "charging",
      "isConnected": true,
      "isCharging": true,
      "currentPower": 11,
      "maxCurrent": 32,
      "powerRateLimit": 11,
      "sessionEnergy": 4.2,
      "phases": 3,
      "voltage": 400
    },
    "conflictStrategies": ["cancel_and_replace", "queue_after"],
    "sessions": true,
    "settings": {
      "max_charge_rate":    { "value": 11, "unit": "kw", "min": 0, "max": 50, "step": 0.1 },
      "max_charge_current": { "value": 32, "unit": "amps", "min": 6, "max": 32, "step": 1 },
      "cable_lock":         { "value": true }
    },
    "vehicle": { "id": "device_veh_001", "links": { "self": "/vehicle/device_veh_001" } },
    "lastAction": null,
    "currentSchedule": null
  },
  "meta": {
    "requestId": "req_5kL9tRcE",
    "environment": "sandbox",
    "timestamp": "2026-08-12T17:58:00.000Z",
    "latencyMs": 28
  }
}
```

The ceiling is 11 kW and a car draws all of it. Store `data.settings.max_charge_rate.value` against the device id and the event id. Store `min`, `max`, and `step` with it. The value you restore must sit inside the same bounds. It must also sit on the same increment grid as the cap.

## Step 2: Write the cap at the event start

Write `max_charge_rate` through the settings endpoint. The body is a sparse map, so send only the key you change.

<Tabs>
  <Tab title="curl">
    ```bash theme={null}
    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": 4.2, "unit": "kw" }
      }'
    ```
  </Tab>

  <Tab title="Node">
    ```javascript theme={null}
    await fetch("https://api.amps.ai/ev-charger/device_ev_001/settings", {
      method: "POST",
      headers: {
        "x-api-key": process.env.AMPS_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        max_charge_rate: { value: 4.2, unit: "kw" },
      }),
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os, requests

    requests.post(
        "https://api.amps.ai/ev-charger/device_ev_001/settings",
        headers={
            "x-api-key": os.environ["AMPS_API_KEY"],
            "Content-Type": "application/json",
        },
        json={"max_charge_rate": {"value": 4.2, "unit": "kw"}},
    )
    ```
  </Tab>
</Tabs>

The response acknowledges the write and lists the keys that changed.

```json theme={null}
{
  "success": true,
  "data": {
    "deviceId": "device_ev_001",
    "updated": ["max_charge_rate"]
  },
  "meta": {
    "requestId": "req_6mM0uSdF",
    "environment": "sandbox",
    "timestamp": "2026-08-12T18:00:03.000Z",
    "latencyMs": 64
  }
}
```

If the operator states the limit in amperes, write `max_charge_current` instead. Never send both keys in one request: they cap the same rate, so the platform refuses the pair with 422 `UNSUPPORTED_SETTING_COMBINATION` rather than a guess. A value outside the declared range, or one between the increments, returns 422 `SETTING_OUT_OF_RANGE`. The refusal carries `min`, `max`, and `step` in `details`, so you can round the value and retry without a second device read.

## Step 3: Verify the charger applied the cap

Check two surfaces, in order. The write response above proves the platform accepted the key. The device read proves the charger stored the value.

```json theme={null}
{
  "success": true,
  "data": {
    "id": "device_ev_001",
    "vendor": "example_vendor_a",
    "sync": { "available": true, "lastPulledAt": "2026-08-12T18:01:10.000Z" },
    "metadata": { "model": "11kW AC Charger", "source": "projection" },
    "state": {
      "status": "charging",
      "isConnected": true,
      "isCharging": true,
      "currentPower": 4.2,
      "maxCurrent": 32,
      "powerRateLimit": 4.2,
      "sessionEnergy": 5.1,
      "phases": 3,
      "voltage": 400
    },
    "conflictStrategies": ["cancel_and_replace", "queue_after"],
    "sessions": true,
    "settings": {
      "max_charge_rate":    { "value": 4.2, "unit": "kw", "min": 0, "max": 50, "step": 0.1 },
      "max_charge_current": { "value": 32, "unit": "amps", "min": 6, "max": 32, "step": 1 },
      "cable_lock":         { "value": true }
    },
    "vehicle": { "id": "device_veh_001", "links": { "self": "/vehicle/device_veh_001" } },
    "lastAction": null,
    "currentSchedule": null
  },
  "meta": { "requestId": "req_7nN1vTeG", "environment": "sandbox", "timestamp": "2026-08-12T18:01:10.000Z", "latencyMs": 31 }
}
```

`data.settings.max_charge_rate.value` holds the cap, and `state.currentPower` has fallen to it.

**A new ceiling does not always slow an active session at once.** Most chargers apply it in seconds. Some vehicles accept a lower limit only after a pause in the session. The behaviour belongs to the brand and to the car, so read the device to confirm it. Do not assume a fault when `currentPower` stays above the cap for a few minutes. If your obligation is hard, push `idle` to stop the session outright. Push `charge` again at the end of the event.

## Step 4: Restore the ceiling at the event end

Write the value you saved in step 1.

```bash theme={null}
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": 11, "unit": "kw" }
  }'
```

```json theme={null}
{
  "success": true,
  "data": {
    "deviceId": "device_ev_001",
    "updated": ["max_charge_rate"]
  },
  "meta": {
    "requestId": "req_8oO2wUfH",
    "environment": "sandbox",
    "timestamp": "2026-08-12T20:00:01.000Z",
    "latencyMs": 58
  }
}
```

**One sharp edge.** The restore overwrites whatever the ceiling holds at that moment. If the home owner or another system changed `max_charge_rate` during the event, your write discards that change. The most recent write always wins, and the API returns no record of who wrote the ceiling last. If that risk matters to you, read the device before you restore. Compare the stored ceiling against the cap you wrote. If the two differ, somebody else moved it, so decide what to do before you overwrite.

## Why this works

A grid event is a constraint on the site for a period of time. It is not an intent for one charging session. The settings surface holds site constraints, and the commands surface holds session intents, which is the actions-versus-settings boundary applied to a charger. Because the ceiling persists, a driver who connects a car during the event also gets the capped rate, with no further call from you. See [canonical actions](/concepts/canonical-actions) for the boundary itself, and [capabilities](/concepts/capabilities) for how a charger declares the settings it accepts.

## What next

<CardGroup cols={2}>
  <Card title="Cap an EV charger's power" icon="gauge" href="/guides/cookbook/ev-charger-set-power">
    The full settings surface behind this recipe.
  </Card>

  <Card title="Charge an exact energy amount" icon="battery-charging" href="/guides/cookbook/ev-charge-energy-amount">
    Deliver a fixed number of kilowatt-hours, then stop.
  </Card>

  <Card title="Smart charging modes" icon="bolt" href="/guides/cookbook/ev-smart-charging">
    Hand timing to the charger's own price or solar optimiser.
  </Card>

  <Card title="EV charger cheat sheet" icon="list-checks" href="/reference/ev-charger-cheat-sheet">
    The whole charger surface in one page.
  </Card>
</CardGroup>

<script
  type="application/ld+json"
  dangerouslySetInnerHTML={{__html: JSON.stringify({
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Cap Charging for a Grid Event",
"description": "Hold an EV charger under a grid operator's power limit for the length of an event, then restore the ceiling you saved.",
"step": [
{ "@type": "HowToStep", "name": "Step 1: Save the current ceiling", "position": 1 },
{ "@type": "HowToStep", "name": "Step 2: Write the cap at the event start", "position": 2 },
{ "@type": "HowToStep", "name": "Step 3: Verify the charger applied the cap", "position": 3 },
{ "@type": "HowToStep", "name": "Step 4: Restore the ceiling at the event end", "position": 4 }
]
})}}
/>
