Plan a batch of chargers to move
A draft batch of the migration's chargers (station_ids, or every charger at location_ids; 500 at most), each in one open batch at a time. Pacing: wave_size chargers move at a time; the next wave starts interval_seconds after the last one settled; the first wave is a canary of canary chargers, after which the batch pauses itself; a share of failures above max_failure_ratio pauses it; a charger refused as busy (charging) is retried in a later wave until idle_timeout_minutes, then blocked, never forced; a move the proxy has not answered after move_timeout_minutes expires and counts as failed. Needs migration:plan (client, support, partner; a key needs stations:write); a narrowed team plans the chargers at its sites only. A retry with the same Idempotency-Key returns the same batch; nothing is created unless its audit entry is stored. Needs an active migration (409 migration_closed when it is paused, completed or archived). Errors: 404 migration_charger_not_in_migration, 404 migration_not_found, 409 migration_charger_in_batch, 409 migration_closed, 503 migration_audit_unavailable. See Errors and statuses.
Path parameters
- migration_idstringRequiredPattern
^mig_[0-9a-f]{32}$
Headers
- idempotency-keystringRequired
Request body
- namestringRequiredA label, such as "Depot, night 1".1–120 characters
- station_idsarray of integer | nullThe chargers to move.
- location_idsarray of integer | nullOr every migration charger at these sites (500 at most).
- pacingPacingInput
Child attributes
- wave_sizeintegerChargers moved at a time: one wave's move requests go out together.Default
5· Minimum 1 · Maximum 50 - interval_secondsintegerSeconds after a wave settled (every charger moved, refused or failed) before the next one starts.Default
60· Minimum 0 · Maximum 86400 - canaryintegerThe first wave's size; the batch then pauses itself until someone resumes it. 0: no canary wave.Default
2· Minimum 0 · Maximum 50 - max_failure_rationumberAfter a wave, the batch pauses itself when more than this share of the chargers it tried failed.Default
0.2· Minimum 0 · Maximum 1 - idle_timeout_minutesintegerA charger the proxy refused because it is charging is retried in a later wave (5 minutes later at the earliest), until this long after its first attempt; then it is blocked (not_idle), never forced.Default
60· Minimum 1 · Maximum 1440 - move_timeout_minutesintegerA move request the proxy has not answered this long after it was sent expires and counts as a failed charger of its wave.Default
30· Minimum 1 · Maximum 1440
Returns · 201
- idstringRequiredbat_...
- migration_idstringRequired
- namestringRequired
- statusenumRequireddraft, submitted (waiting for the client's approval), approved, running, paused, completed, cancelled (moved chargers stay on Ivora) or rolled_back (a rollback of the batch was asked).One of
draft,submitted,approved,running,paused,completed,cancelled,rolled_back - pacingPacingRequired
Child attributes
- wave_sizeintegerRequired
- interval_secondsintegerRequired
- canaryintegerRequired
- max_failure_rationumberRequired
- idle_timeout_minutesintegerRequired
- move_timeout_minutesintegerRequired
- countsobjectRequiredChargers per step, and total (of the caller's sites when narrowed).
- waveintegerRequiredWaves started.
- wave_openbooleanRequiredA wave's moves are out and not all answered.
- next_wave_atstring | nullRequiredWhen the next wave may start (running, between waves).
- paused_reasonenum | nullRequiredWhy a paused batch paused: manual, canary (after its first wave), failure_ratio, rollback_requested (a rollback anywhere in the migration), runner_unhealthy or migration_paused (the migration was paused).One of
manual,canary,failure_ratio,rollback_requested,runner_unhealthy,migration_paused - paused_atstring | nullRequired
- job_idstringRequiredThe job of its moves (GET .../jobs/{job_id}).
- created_bystringRequired
- created_atstringRequired
- updated_atstringRequired
- submitted_bystring | nullRequired
- submitted_atstring | nullRequired
- approvalobject | nullRequiredThe client's approval; null until approved, and again after an edit.
Child attributes
- bystringRequired
- roleenumRequiredOne of
client,support,partner,observer - team_idstring | nullRequired
- atstringRequired
- chargersintegerRequiredChargers in the batch when it was approved.
- digeststringRequiredSHA-256 of the approved charger set and pacing; any edit revokes the approval.
- started_bystring | nullRequiredWho started it, or resumed it last: its moves are asked in their name.
- started_atstring | nullRequired
- finished_atstring | nullRequired
- duration_snumber | nullRequiredSeconds from its start to its end (or now while it runs).
- rollbacksarray of BatchRollbackRequiredRollback jobs of its chargers, with their timings.
Child attributes
- job_idstringRequiredThe rollback job (GET .../jobs/{job_id}).
- requested_atstringRequired
- requested_bystringRequired
- reasonstringRequired
- chargersintegerRequiredChargers it rolls back (skipped ones left out).
- appliedintegerRequiredChargers switched back by the proxy.
- statusenumRequiredOne of
running,succeeded,failed - last_applied_atstring | nullRequiredWhen the proxy switched the last of them back.
- switch_snumber | nullRequiredSeconds from the request to the last switch back.
- chargersarray of BatchCharger | nullRequiredEach charger's step; null in a list.
Child attributes
- station_idintegerRequired
- charger_keystringRequired
- location_idinteger | nullRequired
- stepenumRequiredpending: waiting for its wave (detail busy: refused while charging, retried at retry_at). moving: its move request is out. moved: on Ivora. blocked: not moved (detail not_idle, not_proxied, shadow, rollback_pending). failed: the proxy failed or refused it, or did not answer in time (detail refused_parity, failed, expired). superseded: a rollback took over. skipped: the batch was cancelled or rolled back first, or the charger left the migration (detail).One of
pending,moving,moved,blocked,failed,superseded,skipped - detailstring | nullRequired
- waveinteger | nullRequiredThe wave of its latest move request.
- attemptsintegerRequiredMove requests sent for it (a busy charger is retried).
- request_idstring | nullRequiredIts latest move request (rr_...).
- requested_atstring | nullRequired
- retry_atstring | nullRequiredA busy charger's next attempt at the earliest.
- settled_atstring | nullRequired
- move_snumber | nullRequiredSeconds from its move request to the proxy's report that it moved.
curl --fail-with-body -X POST "https://api.ivoracharge.com/v1/migrations/mig_0123456789abcdef0123456789abcdef/batches" \
-H "Authorization: Bearer $IVORA_API_KEY" \
-H "Idempotency-Key: order-2026-09-30-0001" \
-H "Content-Type: application/json" \
-d '{
"name": "bay-01"
}'{
"id": "id_0123456789abcdef",
"migration_id": "migration_0123456789abcdef",
"name": "bay-01",
"status": "draft",
"pacing": {
"wave_size": 1,
"interval_seconds": 1,
"canary": 1,
"max_failure_ratio": 1.5,
"idle_timeout_minutes": 1,
"move_timeout_minutes": 1
},
"counts": {},
"wave": 1,
"wave_open": false,
"next_wave_at": "2026-09-30T17:00:00Z",
"paused_reason": "manual",
"paused_at": "2026-09-30T17:00:00Z",
"job_id": "job_0123456789abcdef",
"created_by": "string",
"created_at": "2026-09-30T17:00:00Z",
"updated_at": "2026-09-30T17:00:00Z",
"submitted_by": "string",
"submitted_at": "2026-09-30T17:00:00Z",
"approval": {
"by": "string",
"role": "client",
"team_id": "team_0123456789abcdef",
"at": "string",
"chargers": 1,
"digest": "string"
},
"started_by": "string",
"started_at": "2026-09-30T17:00:00Z",
"finished_at": "2026-09-30T17:00:00Z",
"duration_s": 1.5,
"rollbacks": [
{
"job_id": "job_0123456789abcdef",
"requested_at": "2026-09-30T17:00:00Z",
"requested_by": "string",
"reason": "string",
"chargers": 1,
"applied": 1,
"status": "running",
"last_applied_at": "2026-09-30T17:00:00Z",
"switch_s": 1.5
}
],
"chargers": [
{
"station_id": 1,
"charger_key": "string",
"location_id": 7,
"step": "pending",
"detail": "string",
"wave": 1,
"attempts": 1,
"request_id": "request_0123456789abcdef",
"requested_at": "2026-09-30T17:00:00Z",
"retry_at": "2026-09-30T17:00:00Z",
"settled_at": "2026-09-30T17:00:00Z",
"move_s": 1.5
}
]
}Try itproduction · api.ivoracharge.com
Paste a production api key (iv_live_…). Create keys in Developer tools. The key stays in this page's memory, is sent only to https://api.ivoracharge.com and clears when you reload. Test keys are refused.
POST is a write: you confirm the method, path and project before it is sent, with a generated Idempotency-Key.



