Skip to main content

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 Excel CONTROLSTARTINGSTOPNAME)
  • journey.to_stop_name (maps to Excel CONTROLENDINGSTOPNAME)
  • journey.line.slnid
  • journey.line.start
  • journey.line.end
  • journey.carrier_tu_code (maps to Excel CARRIERCODE)
  • executing_tu_code (maps to Excel EXECUTINGORGANIZATION)
  • inspector (maps to Excel TICKETINSPECTOR)
  • 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

EndpointMethodPurposeSuccess CodesError Codes
/controlsPOSTSubmit a provider control batch202400, 401, 403, 422, 429, 500

POST /controls

Submit one complete control batch.

Payload fields

Top-level required:

  • schema_version (must be 1.0)
  • device_id
  • controls (non-empty array, max 500)

Required fields per controls[] item:

  • started_at, partial_close
  • control_grade_pct
  • executing_tu_code
  • inspector
  • journey
  • paper_tickets

Device:

  • device_id required, free string (no strict format)
  • Observed Excel examples: AndId_20e224f7e7d056d4, 11052252, 3633

Control run fields:

  • started_at, partial_close required
  • ended_at optional
  • strict order required: started_at < partial_close and if ended_at exists, partial_close <= ended_at
  • derived inspection key is built from inspector + started_at
  • control_grade_pct required, allowed: 25, 50, 75, 100
  • executing_tu_code required
  • inspector required

Journey:

  • journey required
  • journey.carrier_tu_code required
  • journey.from_stop_name required
  • journey.to_stop_name required
  • journey.line required
  • journey.line.slnid required
  • journey.line.start required
  • journey.line.end required
  • journey.from_stop_sloid required
  • journey.to_stop_sloid required
  • journey.planned_departure required
  • optional: journey.sjyid

Paper tickets:

  • paper_tickets required and non-empty
  • each item requires category, count, timestamp

Field Definitions (Meaning, Required, Format)

Top-level fields:

FieldRequiredMeaning (Provider-facing)Format / RulesNotes
schema_versionYesContract version expected by APIMust be exactly 1.0
device_idYesUnique provider device identifierFree string (no strict format)Observed examples: AndId_20e224f7e7d056d4, 11052252, 3633.
controlsYesBatch of control payloadsNon-empty array, max 500Each item must follow control-item rules below.

Control-item fields (controls[]):

FieldRequiredMeaning (Provider-facing)Format / RulesNotes
started_atYesInspection start timestampISO 8601 date-time with timezone
partial_closeYesInterim close timestampISO 8601 date-time with timezoneMust be greater than started_at.
ended_atNoEnd-of-inspection timestampISO 8601 date-time with timezoneIf present, must be greater than or equal to partial_close.
control_grade_pctYesInspection level/coverage percentageAllowed: 25, 50, 75, 100
executing_tu_codeYesOrganization number of the company executing the controlNumeric string, e.g. 801, 2108Internal mapping: Excel EXECUTINGORGANIZATION. Backend derives tenant_sboid via Fahrplan tbl_TIMETABLE_BusinessOffices.
inspectorYesInspector identifierNon-empty stringInternal mapping: Excel TICKETINSPECTOR. Known example values: e533260, UE67277. Mapping semantics to internal identity model still open.

Journey fields:

FieldRequiredMeaning (Provider-facing)Format / RulesNotes
journey.carrier_tu_codeYesCarrier/company responsible for transport executionNumeric string, e.g. 801, 2108Internal mapping: Excel CARRIERCODE.
journey.from_stop_nameYesBoarding/start stop nameFree text (non-empty)Internal mapping: Excel CONTROLSTARTINGSTOPNAME; Fahrplan source: tbl_TIMETABLE_Stations_Today.designationOfficial.
journey.to_stop_nameYesDestination/end stop nameFree text (non-empty)Internal mapping: Excel CONTROLENDINGSTOPNAME; Fahrplan source: tbl_TIMETABLE_Stations_Today.designationOfficial.
journey.lineYesLine metadata containerObjectContains slnid, start, end.
journey.line.slnidYesSwiss Line IDch:1:slnid:XXXXXX
journey.line.startYesDirection where the line startsFree text (non-empty)
journey.line.endYesDirection where the line endsFree text (non-empty)
journey.sjyidNoSwiss Journey IDCanonical ch:1:sjyid:XXXXXX:XXXXX-XXX; legacy numeric base ID allowed
journey.from_stop_sloidYesBoarding stop SLOIDCanonical ch:1:sloid:XXXXXX; legacy numeric stop ID allowed
journey.to_stop_sloidYesDestination stop SLOIDCanonical ch:1:sloid:XXXXXX; legacy numeric stop ID allowed
journey.planned_departureYesPlanned departure for journey contextISO 8601 date-time with timezone

Paper ticket fields:

FieldRequiredMeaning (Provider-facing)Format / RulesNotes
paper_ticketsYesCaptured paper-ticket aggregatesNon-empty array
paper_tickets[].categoryYesPaper ticket categoryEINZELBILLETT, VERBUNDABO, INCOMING, SONSTIGE
paper_tickets[].countYesNumber of ticketsInteger 0..999
paper_tickets[].timestampYesCapture timestampISO 8601 date-time with timezone

Excel Mapping (NOVA first export)

Review required:

  • CONTROLTIMESTAMP is mapped to started_at.
Excel ColumnV2 API FieldNotes
CONTROLSTARTINGSTOPNAMEjourney.from_stop_nameInternal mapping only; Fahrplan reference: tbl_TIMETABLE_Stations_Today.designationOfficial.
CONTROLENDINGSTOPNAMEjourney.to_stop_nameInternal mapping only; Fahrplan reference: tbl_TIMETABLE_Stations_Today.designationOfficial.
CARRIERCODEjourney.carrier_tu_codeInternal mapping only.
EXECUTINGORGANIZATIONexecuting_tu_codeExample: PostAuto AG uses 801.
TICKETINSPECTORinspectorInternal mapping only. Known samples include e533260, UE67277; exact semantic mapping still unknown.

Validation Notes

  • journey.from_stop_name and journey.to_stop_name must 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_close must 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_code and executing_tu_code are always distinct.
  • Confirm if stop-name fields should be canonical strings or validated against stop registry.