The shape
The knobs that matter
journey: the template the custom journey starts from (e.g.first-successful-charge). It selects the story; an unknown id falls back to the recommended journey.ocpiVersionandtargetIdare advisory in the file. On import the builder runs the journey against whichever target you have selected, so a sample from one target still runs against another, and you do not need a realtargetIdto share a file.clock.mode:acceleratedcompresses a session into seconds;realruns it at wall-clock cadence for long-session testing.session.cadenceSecondsandjitterSeconds: how often meter updates are pushed, and how irregular they are (jitterSecondsabove 0 means irregular).session.updates: which fields each update carries (kwh,total_cost,status,charging_periods).disturbances: faults injected mid-journey to prove the endpoint fails safely. The full set is under Disturbances below.coverageDepth:happy-path,edge-cases, oradversarial.seed: makes a run reproducible; keep it stable to replay the same story.
How do I write my own timeline?
There is one exception to that. A file that spells out its own timedactions list
carries those hand-authored actions into the builder, as the timeline you wrote
rather than the knob editor above.
The Configure step then shows each action’s time, kind, and values, in file order. Click
any value to change it in place. Where an OCPI version defines the field, the builder
names the spec file it comes from.
Timing comes from the file. You can still change the endpoint, the clock, and the seed,
and the run streams and grades exactly like any other custom journey. To change an
action’s kind, its time, or the order of the list, edit the JSON and import it again.
One thing to watch: the run executes each action at its own atSeconds, not in list
order. Keep the list chronological if you want to read it the way it will run.
A file that says journey: 'custom' but lists no actions is refused with a message,
rather than imported and quietly emptied. Asking for a custom journey is not something
the importer should discard on your behalf.
Journeys, packs and what grades them
Three ids in the file name what you are running rather than what it does.What can I put in journey?
journey picks the story to start from. An unknown id falls back to the recommended
journey rather than failing.
first-successful-charge, rough-session, charger-reset, partner-connection,
catalogue-trust, remote-start-stop, live-price-parking, reservation, cdr-desk,
offline-catch-up, hub-routed-charge, book-arrive-charge, direct-terminal-payment,
smart-charging-control, hub-connection-status, invalid-charging-data, and custom
for a timeline you write yourself.
What does journeyPack group?
journeyPack groups journeys by the part of OCPI they exercise: core-charging,
foundation, catalogue, commands, billing, recovery, hub, booking,
direct-payment, charging-profiles, hub-client-info, negative.
What does oracleIds do?
oracleIds on an action names the checks that judge it. An oracle is the thing that
decides whether what came back was right, so this is how a hand-authored action earns a
verdict instead of merely happening:
ocpi_response_success, session_identity, session_progress, session_completed,
cdr_identity, session_cdr_reconciliation, catalogue_identity, command_response,
command_result, billing_reconciliation, pull_window, hub_routing,
booking_lifecycle, payment_reconciliation, charging_profile_result,
hub_client_status.
An action may carry up to 12, and the field is optional: leave it out and the action runs
without a check of its own.
The actions you can write
An action is one thing the runner does at one moment. Every entry needs three things: what to do, when, and which scenarios it provides evidence for.Why is scenarioIds required?
scenarioIds is required on every action, between 1 and 12 of them, each a capital letter
followed by two digits (S01, G13). They are what tie an action to the scenarios your report is
graded against: an action with no scenario would run and prove nothing, so the schema does
not accept one. A file missing them is refused on import rather than run.
atSeconds counts from the start of the run, up to 48 hours. Actions execute at their own
time, not in list order, so keep the list chronological if you want to read it the way it
will run.
Most kinds are named module_verb and send that request to that module, so tariff_put
puts a Tariff and session_get reads a Session back. Once you know the pattern you can
mostly guess the name you want:
The handshake and discovery
versions_get, version_details_get, credentials_get
A charging session, start to finish
prepare_token, session_put, session_patch, session_complete, session_get
The catalogue your partner reads
location_get, location_put, location_patch, tariff_get, tariff_put,
tariff_delete
Billing
cdr_post, cdr_get
Remote control, and the callback it answers with
command_post, await_callback, charging_profile_get, charging_profile_put,
charging_profile_delete
Bookings (OCPI 2.3.0)
booking_get, booking_put, booking_patch, booking_post
Direct payment (the Payments extension)
payment_get, payment_post, payment_put, payment_patch
Hubs
hub_client_info_get, hub_client_info_put
Waiting for your system to call us
expect_inbound, await_inbound
Timing and transport
wait, transport_cut, transport_restore, transport_latency, sandbox_ptp_step
Some of these change state on your side and some only read, which is worth knowing before
you point a list at a live endpoint: a put or a post writes a real object there.
Disturbances
A disturbance is a fault the runner injects on purpose, to see whether your endpoint survives something real rather than only the happy path. Adversity is opt-in: a journey runs clean unless you ask for it.- Session updates:
skip_intermediate_update,duplicate_full_put,zero_energy_pause,non_monotonic_meter,patch_before_put,pending_start,session_never_closes,session_invalid_close,reboot_energy_gap,offline_replay_burst - Charge records:
cdr_before_terminal_session,delay_cdr,early_cdr,duplicate_cdr,credit_cdr,corrected_cdr - Pricing and parking:
tariff_boundary,parking_period - Callbacks:
callback_timeout,callback_duplicate,callback_out_of_order - Transport:
transport_outage
The values an action carries
Each hand-authored action can carry a bag of named values, in the file or added in the builder:What can a value be?
A value is text, a number,true, false, or null. A list or an object is refused
in the builder, because a structure belongs in the JSON file rather than in a
single-line editor. Types survive the round trip: 16 comes back as the number your
file held, not as the string "16".
An action can hold up to 40 values, and a name can be up to 64 characters.
Six names belong to the server and an action cannot set them: url, headers,
authorization, token, template, and expression. These carry the request itself,
so a scenario that could overwrite them could point a run at somewhere you did not
choose.
Which keys does the runner check?
Most keys are yours to name. A few are read by the runner, which means it also checks them. Being on this list is not the same as being in the specification, and the two are marked separately below because they are different kinds of thing:ocpp_status is the case worth understanding. No OCPI version names it, and we do not
pretend otherwise: the editor labels it a partner extension exactly as it labels a name
you invent yourself. The runner reads it only so that a value you did supply is checked
rather than silently shipped empty, and so a PATCH can carry the CSMS status your
platform reports alongside the OCPI one. Nothing about it being on this list makes it
standard.
Where a key is one of these, the editor says so while you type, and an empty value is
refused rather than saved into a run that Preview would reject.
Can I send a field OCPI does not define?
Any other name is yours. The editor labels it a partner extension and tells you it goes on the wire exactly as you write it, so you can model something your platform sends that the specification never named. This is deliberate on our side and allowed on the receiving side. OCPI 2.3.0 puts it plainly: “An OCPI Platform SHALL NOT reject request or response payloads based on the presence of JSON object field names that are not documented in this specification.” A partner who refuses your extra field is the one out of line, and a run that sends one is a fair way to find that out before production does. Two things worth knowing. An extension is not graded, because there is no clause to grade it against. And a key the runner does not read may be left empty, where a key it does read may not.Import, run, and save
- On Charging Journeys, choose Import scenario JSON and pick your file, or Download sample to start from a working one.
- The custom journey opens in the builder on the Configure step with your knobs applied. Adjust anything, then Preview to compile the plan.
- Start the run. It streams live and lands a graded report in Runs, stored on your account, replayable and runnable from CI with the same JSON.
// comments and trailing commas; the importer
strips them. The API and CI expect strict JSON.
See also Run a charging journey for the run, follow,
and recovery flow.