Quickstart
This guide takes you from an API key to a completed charging session. You’ll register a charger, start a session on one of its connectors, stop it, and read back the session and its billing record. Every call below is a real request against the Ampr API.
All requests are made to https://api.ampr.dev/v1. A single-resource
response is wrapped in a data key; a list response adds a pagination
key alongside it.
Authenticate
Every request needs an Authorization: Bearer <api_key> header. Grab your
first key from the dashboard under Settings → API keys. Once you have
one, you can create and revoke additional keys programmatically with
POST /api-keys.
Use your key to confirm it works by fetching your organization:
curl https://api.ampr.dev/v1/organization \
-H "Authorization: Bearer $AMPR_API_KEY" const res = await fetch('https://api.ampr.dev/v1/organization', {
headers: {
Authorization: `Bearer ${process.env.AMPR_API_KEY}`,
},
});
const { data: org } = await res.json();
console.log(org.id, org.plan);
// org_... "sandbox" A 401 here means the key is missing, revoked, or malformed. Every
subsequent call in this guide reuses the same header.
Register a charger
Chargers are registered with their serial, vendor, and model. Ampr assigns
the charger a chg_-prefixed id and puts it in pending status until it
connects over OCPP and the claim resolves.
curl https://api.ampr.dev/v1/chargers \
-H "Authorization: Bearer $AMPR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"serial": "ABC-001",
"vendor": "ABB",
"model": "Terra AC W22-T-0"
}' const res = await fetch('https://api.ampr.dev/v1/chargers', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AMPR_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
serial: 'ABC-001',
vendor: 'ABB',
model: 'Terra AC W22-T-0',
}),
});
const { data: charger } = await res.json();
console.log(charger.id, charger.status);
// chg_2kT8v9xBn4 "pending" {
"data": {
"id": "chg_2kT8v9xBn4",
"serial": "ABC-001",
"vendor": "ABB",
"model": "Terra AC W22-T-0",
"firmware_version": null,
"status": "pending",
"location_id": null,
"tariff_id": null,
"claim_expires_at": "2026-07-16T12:00:00Z",
"sockets": [],
"created_at": "2026-07-14T12:00:00Z"
}
}
The claim expires in 48 hours if the physical charger never connects. Once it
does, GET /chargers/{charger_id} returns a populated sockets array, each
with its own skt_-prefixed id. The rest of this guide uses
skt_7mR3pQw1 as that connector’s id.
Start a session
Sessions are started per connector, not per charger. A dual-socket charger
has two independently addressable sockets. Pass the id_tag of the card or
app authorizing the session:
curl "https://api.ampr.dev/v1/chargers/chg_2kT8v9xBn4/sockets/skt_7mR3pQw1/start?wait=true" \
-H "Authorization: Bearer $AMPR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"id_tag": "04A1B2C3D4E5"}' const res = await fetch(
'https://api.ampr.dev/v1/chargers/chg_2kT8v9xBn4/sockets/skt_7mR3pQw1/start?wait=true',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AMPR_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ id_tag: '04A1B2C3D4E5' }),
}
);
const { data: command } = await res.json();
console.log(command.id, command.status);
// cmd_4jK8rWx6 "accepted" {
"data": {
"id": "cmd_4jK8rWx6",
"type": "RemoteStartTransaction",
"charger_id": "chg_2kT8v9xBn4",
"socket_id": "skt_7mR3pQw1",
"status": "accepted",
"error": null,
"created_at": "2026-07-14T12:01:00Z",
"completed_at": "2026-07-14T12:01:02Z"
}
}
wait=true blocks (up to timeout seconds, default 30) until the charger
acknowledges the command, so you get a 200 with a final status in one
round trip. Omit it and you get a 202 immediately with status: "pending". Poll the command or listen for its webhook if you’d rather not
block.
Stop the session
Stopping works the same way, on the same socket, with no request body:
curl -X POST "https://api.ampr.dev/v1/chargers/chg_2kT8v9xBn4/sockets/skt_7mR3pQw1/stop?wait=true" \
-H "Authorization: Bearer $AMPR_API_KEY" const res = await fetch(
'https://api.ampr.dev/v1/chargers/chg_2kT8v9xBn4/sockets/skt_7mR3pQw1/stop?wait=true',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AMPR_API_KEY}`,
},
}
);
const { data: command } = await res.json();
console.log(command.type, command.status);
// "RemoteStopTransaction" "accepted" See the result
While the session was active, the connector’s current_session_id (from
GET /chargers/{charger_id}/sockets/{socket_id}) pointed at it. Fetch that
session directly:
curl https://api.ampr.dev/v1/sessions/ses_9nL5tYz2 \
-H "Authorization: Bearer $AMPR_API_KEY" const res = await fetch('https://api.ampr.dev/v1/sessions/ses_9nL5tYz2', {
headers: {
Authorization: `Bearer ${process.env.AMPR_API_KEY}`,
},
});
const { data: session } = await res.json();
console.log(session.status, session.total_energy_wh, session.cdr_id);
// "completed" 8420 "cdr_1hF3mNv8" {
"data": {
"id": "ses_9nL5tYz2",
"charger_id": "chg_2kT8v9xBn4",
"socket_id": "skt_7mR3pQw1",
"token_id": "trk_6pS2qUy4",
"status": "completed",
"start_time": "2026-07-14T12:01:02Z",
"end_time": "2026-07-14T12:41:17Z",
"meter_start": 128400,
"meter_stop": 136820,
"stop_reason": "Remote",
"total_energy_wh": 8420,
"duration_seconds": 2415,
"meter_values": [],
"cdr_id": "cdr_1hF3mNv8"
}
}
status moves from active to completed once the charger confirms the
stop. The session’s cdr_id points at its Charge Detail Record, the
immutable billing receipt for what just happened. Fetch it with
GET /cdrs/cdr_1hF3mNv8, or list every CDR for this charger with
GET /cdrs?charger_id=chg_2kT8v9xBn4.
That’s the full loop: register, start, stop, bill. From here, see the handle webhooks guide to get notified instead of polling, the bill a session guide for how billing decisions are made when meter data is incomplete, and the connect an OCPP charger guide for what happens on the wire between registration and the claim resolving.