Mapping API Provider With NOVA Data
Provider contract aligned with the first NOVA Excel export (kplus_short_export.xlsx).
Status: Draft for review before runtime/OpenAPI implementation changes.
Scope
- API surface:
POST /api/provider/v1/controls - Runtime target: Data Service (
services/data-service) - Auth model: OAuth2 client credentials (JWT bearer)
- Processing model: synchronous ingest + asynchronous enrichment
- Contract mode: NOVA-aligned provider contract
Why this exists
The first NOVA Excel export introduces/clarifies business fields required by current provider integrations. This guide captures those fields so providers can send data aligned with the current export semantics.
Contract Highlights
New mandatory fields:
journey.from_stop_name(maps to ExcelCONTROLSTARTINGSTOPNAME)journey.to_stop_name(maps to ExcelCONTROLENDINGSTOPNAME)journey.line.slnidjourney.line.startjourney.line.endjourney.carrier_tu_code(maps to ExcelCARRIERCODE)executing_tu_code(maps to ExcelEXECUTINGORGANIZATION)inspector(maps to ExcelTICKETINSPECTOR)partial_close
Clarified business meaning:
journey.carrier_tu_code= TU/company responsible for transport execution.executing_tu_code= company executing the control (example: PostAuto AG =801).inspector= inspector identifier (mapping semantics still under clarification).- Inspection identity is derived from
inspector+ control timestamp (started_at). partial_close= interim close point of the inspection run.ended_at= optional end-of-inspection timestamp.
Endpoint Summary
| Endpoint | Method | Purpose | Success Codes | Error Codes |
|---|---|---|---|---|
/controls | POST | Submit a provider control batch | 202 | 400, 401, 403, 422, 429, 500 |
POST /controls
Submit one complete control batch.
Payload fields
Top-level required:
schema_version(must be1.0)device_idcontrols(non-empty array, max 500)
Required fields per controls[] item:
started_at,partial_closecontrol_grade_pctexecuting_tu_codeinspectorjourneypaper_tickets
Device:
device_idrequired, free string (no strict format)- Observed Excel examples:
AndId_20e224f7e7d056d4,11052252,3633
Control run fields:
started_at,partial_closerequiredended_atoptional- strict order required:
started_at < partial_closeand ifended_atexists,partial_close <= ended_at - derived inspection key is built from
inspector+started_at control_grade_pctrequired, allowed:25,50,75,100executing_tu_coderequiredinspectorrequired
Journey:
journeyrequiredjourney.carrier_tu_coderequiredjourney.from_stop_namerequiredjourney.to_stop_namerequiredjourney.linerequiredjourney.line.slnidrequiredjourney.line.startrequiredjourney.line.endrequiredjourney.from_stop_sloidrequiredjourney.to_stop_sloidrequiredjourney.planned_departurerequired- optional:
journey.sjyid
Paper tickets:
paper_ticketsrequired and non-empty- each item requires
category,count,timestamp
Field Definitions (Meaning, Required, Format)
Top-level fields:
| Field | Required | Meaning (Provider-facing) | Format / Rules | Notes |
|---|---|---|---|---|
schema_version | Yes | Contract version expected by API | Must be exactly 1.0 | |
device_id | Yes | Unique provider device identifier | Free string (no strict format) | Observed examples: AndId_20e224f7e7d056d4, 11052252, 3633. |
controls | Yes | Batch of control payloads | Non-empty array, max 500 | Each item must follow control-item rules below. |
Control-item fields (controls[]):
| Field | Required | Meaning (Provider-facing) | Format / Rules | Notes |
|---|---|---|---|---|
started_at | Yes | Inspection start timestamp | ISO 8601 date-time with timezone | |
partial_close | Yes | Interim close timestamp | ISO 8601 date-time with timezone | Must be greater than started_at. |
ended_at | No | End-of-inspection timestamp | ISO 8601 date-time with timezone | If present, must be greater than or equal to partial_close. |
control_grade_pct | Yes | Inspection level/coverage percentage | Allowed: 25, 50, 75, 100 | |
executing_tu_code | Yes | Organization number of the company executing the control | Numeric string, e.g. 801, 2108 | Internal mapping: Excel EXECUTINGORGANIZATION. Backend derives tenant_sboid via Fahrplan tbl_TIMETABLE_BusinessOffices. |
inspector | Yes | Inspector identifier | Non-empty string | Internal mapping: Excel TICKETINSPECTOR. Known example values: e533260, UE67277. Mapping semantics to internal identity model still open. |
Journey fields:
| Field | Required | Meaning (Provider-facing) | Format / Rules | Notes |
|---|---|---|---|---|
journey.carrier_tu_code | Yes | Carrier/company responsible for transport execution | Numeric string, e.g. 801, 2108 | Internal mapping: Excel CARRIERCODE. |
journey.from_stop_name | Yes | Boarding/start stop name | Free text (non-empty) | Internal mapping: Excel CONTROLSTARTINGSTOPNAME; Fahrplan source: tbl_TIMETABLE_Stations_Today.designationOfficial. |
journey.to_stop_name | Yes | Destination/end stop name | Free text (non-empty) | Internal mapping: Excel CONTROLENDINGSTOPNAME; Fahrplan source: tbl_TIMETABLE_Stations_Today.designationOfficial. |
journey.line | Yes | Line metadata container | Object | Contains slnid, start, end. |
journey.line.slnid | Yes | Swiss Line ID | ch:1:slnid:XXXXXX | |
journey.line.start | Yes | Direction where the line starts | Free text (non-empty) | |
journey.line.end | Yes | Direction where the line ends | Free text (non-empty) | |
journey.sjyid | No | Swiss Journey ID | Canonical ch:1:sjyid:XXXXXX:XXXXX-XXX; legacy numeric base ID allowed | |
journey.from_stop_sloid | Yes | Boarding stop SLOID | Canonical ch:1:sloid:XXXXXX; legacy numeric stop ID allowed | |
journey.to_stop_sloid | Yes | Destination stop SLOID | Canonical ch:1:sloid:XXXXXX; legacy numeric stop ID allowed | |
journey.planned_departure | Yes | Planned departure for journey context | ISO 8601 date-time with timezone |
Paper ticket fields:
| Field | Required | Meaning (Provider-facing) | Format / Rules | Notes |
|---|---|---|---|---|
paper_tickets | Yes | Captured paper-ticket aggregates | Non-empty array | |
paper_tickets[].category | Yes | Paper ticket category | EINZELBILLETT, VERBUNDABO, INCOMING, SONSTIGE | |
paper_tickets[].count | Yes | Number of tickets | Integer 0..999 | |
paper_tickets[].timestamp | Yes | Capture timestamp | ISO 8601 date-time with timezone |
Excel Mapping (NOVA first export)
Review required:
CONTROLTIMESTAMPis mapped tostarted_at.
| Excel Column | V2 API Field | Notes |
|---|---|---|
CONTROLSTARTINGSTOPNAME | journey.from_stop_name | Internal mapping only; Fahrplan reference: tbl_TIMETABLE_Stations_Today.designationOfficial. |
CONTROLENDINGSTOPNAME | journey.to_stop_name | Internal mapping only; Fahrplan reference: tbl_TIMETABLE_Stations_Today.designationOfficial. |
CARRIERCODE | journey.carrier_tu_code | Internal mapping only. |
EXECUTINGORGANIZATION | executing_tu_code | Example: PostAuto AG uses 801. |
TICKETINSPECTOR | inspector | Internal mapping only. Known samples include e533260, UE67277; exact semantic mapping still unknown. |
Validation Notes
journey.from_stop_nameandjourney.to_stop_namemust be present and non-empty.- For best station matching quality, stop names should match Fahrplan canonical spelling from
tbl_TIMETABLE_Stations_Today.designationOfficial(including punctuation and umlauts). journey.carrier_tu_code,executing_tu_code,inspector,partial_closemust be present and non-empty.- Validation rules in this document define the current contract.
Request example
{
"schema_version": "1.0",
"device_id": "AndId_c428366d643e9ce2",
"controls": [
{
"started_at": "2026-03-09T08:00:00Z",
"partial_close": "2026-03-09T08:10:00Z",
"ended_at": "2026-03-09T08:20:00Z",
"control_grade_pct": 75,
"executing_tu_code": "801",
"inspector": "UE67277",
"journey": {
"carrier_tu_code": "801",
"sjyid": "ch:1:sjyid:100058:12952-002",
"line": {
"slnid": "ch:1:slnid:103456",
"start": "Bernau (Schw), Poche",
"end": "Neuenburg (Baden), Bahnhof"
},
"from_stop_sloid": "ch:1:sloid:8578391",
"to_stop_sloid": "ch:1:sloid:8578391",
"from_stop_name": "Bernau (Schw), Poche",
"to_stop_name": "Neuenburg (Baden), Bahnhof",
"planned_departure": "2026-03-09T08:06:00Z"
},
"paper_tickets": [
{
"category": "EINZELBILLETT",
"count": 2,
"timestamp": "2026-03-09T08:09:00Z"
}
]
}
]
}
Open items
- Confirm whether
journey.carrier_tu_codeandexecuting_tu_codeare always distinct. - Confirm if stop-name fields should be canonical strings or validated against stop registry.