Dry-run a network import, or apply a dry run
Moves an existing network (locations, chargers as stations, their EVSEs and connectors) into the project. A dry run is the default: send text/csv (the template), or JSON {"source": "ocpi_locations"} with an OCPI 2.2.1 Locations document or a feed (the incumbent's Locations module URL and the token it issued you, read with GET requests only, over public https; the token is used for this request alone and never stored). At most 5,000 EVSEs, 20,000 source rows (CSV rows, or OCPI Locations and EVSEs) and 8 MiB. The answer (201) is the plan: every location and charger as create, update, skip or error with the reason (duplicates in the file, chargers that exist in this or another project, missing coordinates or time zone, unknown connector types, charger IDs that do not fit the project's rules). Nothing is written. Then POST again with apply=true and dry_run_id (no body, an Idempotency-Key): apply writes exactly what the dry run showed, in batches, and answers 200 with the station, location and connector IDs; 409 import_stale when the project changed since, with nothing written. After a 503 outcome_unknown or a partial import, apply again with a new key: it resumes. Chargers keep their own IDs: under the project's charger URL where per-project charger URLs are on (name p<tenant_id>-<charger_id>), else as global OCPP connection names. Once the global charger URL is closed to new registrations in an environment, a charger to create under a global name is an error row global_charger_url_retired and apply answers 409 global_charger_url_retired: staff turn per-project charger URLs on for the project first. No charger is contacted. Requires a team owner or admin of the project (projects:manage) signed in, or Ivora staff (signed in, or a staff key with stations:write), or an API key holding migration:import: a project key of this project (only the team's owners and admins, and Ivora administrators, grant that scope; developers cannot), or a team migration key of this project's active migration whose owner's role there holds it over every site. A key makes at most 10 dry runs and applies a minute (429 rate_limited with Retry-After). Each dry run and apply is audited (network_import.dry_run, network_import.applied) with the key and who made it. Only the dry run's maker applies it: the same key, or a signed-in member of the same team (403 forbidden otherwise). A team migration key made before keys reached these routes is refused (403 migration_key_refused): make a new one. Errors: 402 billing_suspended, 402 payment_method_required, 404 import_not_found, 409 global_charger_url_retired, 409 import_applied, 409 import_in_progress, 409 import_reverted, 409 import_stale, 409 request_in_progress, 409 self_serve_charger_cap, 413 request_too_large, 415 unsupported_media_type, 422 feed_failed, 422 feed_invalid, 422 feed_refused, 422 feed_too_large, 422 import_too_large, 503 outcome_unknown. See Errors and statuses.
Path parameters
- tenant_idintegerRequired
Query parameters
- applybooleanApply the dry run named by dry_run_idDefault
false - dry_run_idstring | nullThe dry run to apply (its id)Pattern
^imp_[0-9a-f]{32}$
Headers
- idempotency-keystring | nullRequired with apply=true
Request body (optional)
- sourcestringRequired
- documentobject | array of any | nullAn OCPI 2.2.1 Locations response ({"data": [...]}), a list of Location objects or one Location
- feedany | null
- charger_mapobject | nullEVSE uid to the charger it belongs to: "CP001" or {"charger_id": "CP001", "evse_number": 2, "ocpp_version": "1.6"}. Without an entry an EVSE is its own charger, with its uid as charger_id
Returns · 200
- idstringRequired
- tenant_idintegerRequired
- migration_idstring | nullThe migration this import belongs to (made under /v1/migrations/{migration_id}/imports): its applied stations join that migration as imported. null for a project import.
- sourceenumRequiredOne of
csv,ocpi_locations - originstring | nullRequiredThe fetched feed's host and path (no query string or token); null for an upload
- statusenumRequiredOne of
planned,applying,applied,partial,reverted,partially_reverted - identityenumRequiredproject: chargers keep their own IDs under the project's charger URL; global: each charger ID is a globally unique OCPP connection nameOne of
project,global - countsImportCountsRequired
Child attributes
- createintegerRequired
- updateintegerRequired
- skipintegerRequired
- errorintegerRequired
- totalsImportTotalsRequired
Child attributes
- locationsintegerRequiredLocations in the source
- stationsintegerRequiredChargers in the source, each one station
- evsesintegerRequired
- connectorsintegerRequired
- actorstringRequired
- created_atstringRequired
- updated_atstringRequired
- applied_atstring | nullRequired
- reverted_atstring | nullRequired
- rowsarray of ImportRowRequired
Child attributes
- itemstring | nullRequiredThe row's ID in this import (L<n> for a location, S<n> for a station); null for a source row that could not be read
- kindenumRequiredOne of
location,station,row - actionenumRequiredWhat apply does: create, update (change the existing resource), skip (identical, or removed in the source) or error (nothing is written for it)One of
create,update,skip,error - stateenumRequiredplanned in a dry run; after apply pending, done, failed or skipped; after a revert reverted or keptOne of
planned,pending,done,failed,skipped,reverted,kept - sourcestring | nullRequiredWhere the row comes from: CSV line numbers, or the position in the OCPI document
- refstring | nullA location's reference: the CSV location_ref or the OCPI Location id, stored as its external_reference
- charger_idstring | null
- namestring | nullThe station's OCPP connection name in Ivora
- location_refstring | null
- location_idinteger | null
- station_idinteger | null
- connector_idsarray of integer | nullThe station's connector resource IDs, once applied
- evsesinteger | null
- connectorsinteger | null
- changesarray of stringThe fields an update changes
- codestring | null
- messagestring | null
- warningsarray of string
- migration_stateenum | nullA migration's import (migration_id): the station's state on the migration's board once it joined (imported first); null while it is not in this migration (not applied yet, or in another migration). null on a project import.One of
imported,proxied,shadow,parity_checked,moved,rolling_back,rolled_back - charger_keystring | nullA migration's import: the charger proxy's routing key the station joined with, <project>/<charger id> (or the global connection name); null while not in the migration.
- follow_upsarray of stringRequiredSteps outside this import: RFID tokens, tariffs, EVSE IDs for roaming, credentials
curl --fail-with-body -X POST "https://api.ivoracharge.com/v1/tenants/1042/imports" \
-H "Authorization: Bearer $IVORA_API_KEY" \
-H "Idempotency-Key: order-2026-09-30-0001" \
-H "Content-Type: application/json" \
-d '{
"source": "ocpi_locations"
}'{
"id": "id_0123456789abcdef",
"tenant_id": 1042,
"migration_id": "migration_0123456789abcdef",
"source": "csv",
"origin": "string",
"status": "planned",
"identity": "project",
"counts": {
"create": 1,
"update": 1,
"skip": 1,
"error": 1
},
"totals": {
"locations": 1,
"stations": 1,
"evses": 1,
"connectors": 1
},
"actor": "string",
"created_at": "2026-09-30T17:00:00Z",
"updated_at": "2026-09-30T17:00:00Z",
"applied_at": "2026-09-30T17:00:00Z",
"reverted_at": "2026-09-30T17:00:00Z",
"rows": [
{
"item": "string",
"kind": "location",
"action": "create",
"state": "planned",
"source": "string",
"ref": "string",
"charger_id": "charger_0123456789abcdef",
"name": "bay-01",
"location_ref": "string",
"location_id": 7,
"station_id": 1,
"connector_ids": [
1
],
"evses": 1,
"connectors": 1,
"changes": [
"string"
],
"code": "string",
"message": "string",
"warnings": [
"string"
],
"migration_state": "imported",
"charger_key": "string"
}
],
"follow_ups": [
"string"
]
}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.



