Übersicht
OL-Events.ch bietet eine REST-API an, die auf dem IOF Datastandard 3.0 basiert. Externe Auswertungsapplikationen können darüber Anmeldungen abrufen, Startlisten austauschen, Resultate hochladen und Funkposten pflegen. Den Token findest du unter Token für die Auswertungssoftware finden.
Base-URL: https://ol-events.ch/api/
Authentifizierung
Alle API-Requests erfordern einen Bearer Token im Authorization-Header.
Jeder Lauf (Race) hat einen eigenen Token, der im Lauf-Admin unter Export → API einsehbar ist.
Authorization: Bearer <race-bearer-token>
Beispiel:
curl -H "Authorization: Bearer abc123def456..." \
https://ol-events.ch/api/iof/v1/races/42/entrylist
Bei ungültigem oder fehlendem Token wird HTTP 403 Forbidden zurückgegeben.
Hinweis: Der Token ist an einen spezifischen Lauf gebunden. Für Endpunkte ohne
{race}-Parameter (z.B. EventList) wird der Lauf automatisch anhand des Tokens ermittelt.
Ids und Zuordnung
Ids einer Person
| Id | XML-Pfad | Bedeutung |
|---|---|---|
| SOLV-Nr. | Person/Id |
Wird am Format erkannt (zwei Buchstaben, eine Ziffer, drei Buchstaben, z. B. AB1CDE). type spielt keine Rolle. |
| IOF-Nr. | Person/Id[@type="IOF"] |
type="IOF" ist Pflicht. |
| Unsere Id |
Person/Id[@type="ol-events.ch"] oder EntryId
|
Die race_runner.id aus der EntryList (PersonEntry/Id). |
Achtung: Jede andere
Person/Idliest der Import als unsere Id. Eine IOF-Nr. ohnetype="IOF"kann ein Resultat deshalb mit einer fremden Anmeldung verknüpfen.
Eine importierte Person wird über Name, Jahrgang, Geschlecht, SOLV-Nr., unsere Id und Kategorie wiedererkannt. Ändert sich einer dieser Werte, entsteht eine neue Zeile. Vor einem Formatwechsel deshalb alle Resultate des Laufs löschen.
Mit einem Läuferkonto verknüpft wird in dieser Reihenfolge: SOLV-Nr., unsere Id, IOF-Nr.
Teams
TeamEntry/Id ist im Einzellauf die race_runner.id (Gruppen und Familien), im Team-Lauf die teams.id.
TeamResult und TeamStart erkennt der Import in dieser Reihenfolge:
EntryIdBibNumberName- Mitglieder
Wir empfehlen, TeamEntry/Id als EntryId zurückzugeben. Der Name allein ist kein Schlüssel: Zwei Teams können gleich heissen oder ihren Namen ändern.
Endpunkte
GET /api/iof/v1/eventlist
Gibt die Event-Informationen zurück, die dem verwendeten Bearer Token zugeordnet sind.
Response: application/xml — IOF 3.0 EventList
<?xml version="1.0" encoding="UTF-8"?>
<EventList xmlns="http://www.orienteering.org/datastandard/3.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
iofVersion="3.0"
createTime="2026-03-12T10:00:00+01:00"
creator="ol-events.ch">
<Event>
<Name>Beispiel OL 2026</Name>
<StartTime>
<Date>2026-06-15</Date>
</StartTime>
</Event>
</EventList>
GET /api/iof/v1/races/{race}/classlist
Gibt die Kategorien (Klassen) eines Laufs zurück.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Response: application/xml — IOF 3.0 ClassList
<?xml version="1.0" encoding="UTF-8"?>
<ClassList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
createTime="2026-03-12T10:00:00+01:00"
creator="ol-events.ch">
<Class>
<Id>101</Id>
<Name>H20</Name>
<ShortName>H20</ShortName>
</Class>
<Class>
<Id>102</Id>
<Name>D20</Name>
<ShortName>D20</ShortName>
</Class>
</ClassList>
GET /api/iof/v1/races/{race}/entrylist
Gibt alle gültigen Anmeldungen eines Laufs zurück: bezahlt, offen exportiert und extern bezahlt.
Die Liste ist immer der Gesamtstand. Stornierte Anmeldungen fehlen ohne Kennzeichen. Beim Abgleich deshalb nur Einträge mit unserer Id entfernen, die in der Liste fehlen und noch nicht gestartet sind.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Response: application/xml — IOF 3.0 EntryList
Jede Anmeldung enthält:
- Persönliche Daten (Name, Jahrgang, Geschlecht)
- Verein (Organisation)
- Kategorie (Class)
- SI-Card-Nummer (ControlCard)
- Anmeldegebühr (AssignedFee)
- Startzeitwunsch (StartTimeAllocationRequest), falls vorhanden
- Startnummer und Startzeit (in Extensions), falls bereits zugewiesen
Alle ol-events.ch-spezifischen Elemente in Extensions (z. B. BibNumber, StartTime, CalculatedBlock, SolvClubId, SolvClassId) stehen im Namespace https://ol-events.ch/iof-extensions. Das IOF-Schema erlaubt in Extensions nur Elemente aus einem fremden Namespace; so bleibt die Datei gegen IOF.xsd gültig.
<?xml version="1.0" encoding="UTF-8"?>
<EntryList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
createTime="2026-03-12T10:00:00+01:00"
creator="ol-events.ch">
<Event>
<Name>Beispiel OL 2026</Name>
</Event>
<TeamEntry modifyTime="2026-02-20T14:30:00+01:00">
<Id type="ol-events.ch">501</Id>
<Name>OLG Beispiel 1</Name>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<TeamEntryPerson>
<Person sex="M">
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
</Person>
<Leg>1</Leg>
<ControlCard punchingSystem="SI">234567</ControlCard>
</TeamEntryPerson>
<TeamEntryPerson>
<Person sex="F">
<Name>
<Family>Beispiel</Family>
<Given>Anna</Given>
</Name>
</Person>
<Leg>2</Leg>
<ControlCard punchingSystem="SI">345678</ControlCard>
</TeamEntryPerson>
<Class>
<Id>201</Id>
<Name>Staffel Offen</Name>
</Class>
</TeamEntry>
<PersonEntry modifyTime="2026-02-20T14:30:00+01:00">
<Id type="ol-events.ch">12345</Id>
<Person sex="M">
<Id type="IOF">123456</Id>
<Id type="SOLV">AB1CDE</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
<BirthDate>1990-01-01</BirthDate>
</Person>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<ControlCard punchingSystem="SI">234567</ControlCard>
<Class>
<Id>101</Id>
<Name>H20</Name>
</Class>
<AssignedFee>
<Fee>
<Name>total</Name>
<Amount currency="CHF">25.00</Amount>
</Fee>
<PaidAmount currency="CHF">25.00</PaidAmount>
</AssignedFee>
<EntryTime>2026-02-15T09:00:00+01:00</EntryTime>
<Extensions>
<BibNumber xmlns="https://ol-events.ch/iof-extensions">42</BibNumber>
<StartTime xmlns="https://ol-events.ch/iof-extensions">10:30:00+01:00</StartTime>
</Extensions>
</PersonEntry>
</EntryList>
GET /api/iof/v1/races/{race}/startlist
Gibt die Startliste aus den Anmeldungen auf ol-events.ch zurück. Eine hochgeladene Startliste erscheint hier nicht.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Response: application/xml — IOF 3.0 StartList
<?xml version="1.0" encoding="UTF-8"?>
<StartList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
createTime="2026-03-12T10:00:00+01:00"
creator="ol-events.ch">
<Event>
<Name>Beispiel OL 2026</Name>
</Event>
<ClassStart>
<Class>
<Id>101</Id>
<Name>H20</Name>
</Class>
<PersonStart>
<EntryId type="ol-events.ch">12345</EntryId>
<Person sex="M">
<Id type="IOF">123456</Id>
<Id type="SOLV">AB1CDE</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
<BirthDate>1990-01-01</BirthDate>
</Person>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<Start>
<StartTime>2026-06-15T10:30:00+02:00</StartTime>
<ControlCard punchingSystem="SI">234567</ControlCard>
</Start>
</PersonStart>
</ClassStart>
</StartList>
POST /api/iof/v1/races/{race}/startlist
Importiert eine Startliste in einen Lauf. Bestehende Einträge werden wiedererkannt und aktualisiert, siehe Ids und Zuordnung.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Request:
-
Content-Type:
application/xml -
Body: IOF 3.0
StartListXML
curl -X POST \
-H "Authorization: Bearer abc123def456..." \
-H "Content-Type: application/xml" \
--data-binary @startlist.xml \
https://ol-events.ch/api/iof/v1/races/42/startlist
Erwartetes XML-Format im Request-Body:
<?xml version="1.0" encoding="UTF-8"?>
<StartList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
creator="ZORA">
<Event>
<Name>Beispiel OL 2026</Name>
</Event>
<ClassStart>
<Class>
<Name>H20</Name>
</Class>
<PersonStart>
<EntryId type="ol-events.ch">12345</EntryId>
<Person sex="M">
<Id type="IOF">123456</Id>
<Id type="SOLV">AB1CDE</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
<BirthDate>1990-01-01</BirthDate>
</Person>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<Start>
<BibNumber>42</BibNumber>
<StartTime>2026-06-15T10:30:00+02:00</StartTime>
</Start>
</PersonStart>
<TeamStart>
<EntryId type="ol-events.ch">501</EntryId>
<Name>OLG Beispiel 1</Name>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<BibNumber>10</BibNumber>
<TeamMemberStart>
<Person sex="M">
<Id type="IOF">123456</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
</Person>
<Start>
<Leg>1</Leg>
<StartTime>2026-06-15T10:30:00+02:00</StartTime>
</Start>
</TeamMemberStart>
</TeamStart>
</ClassStart>
</StartList>
Importierte Felder pro Läufer:
| Feld | XML-Pfad | Beschreibung |
|---|---|---|
| Nachname | Person/Name/Family |
Pflichtfeld |
| Vorname | Person/Name/Given |
Pflichtfeld |
| Kategorie |
Class/ShortName, sonst Class/Name
|
Zuordnung über das Kürzel; wird bei Bedarf automatisch erstellt |
| Startzeit | Start/StartTime |
ISO 8601 Datetime |
| Startnummer | Start/BibNumber |
Optional |
| Verein | Organisation/Name |
Optional |
| IOF-Nr. | Person/Id[@type="IOF"] |
Siehe Ids und Zuordnung |
| SOLV-Nr. | Person/Id |
Am Format erkannt |
| Unsere Id |
Person/Id[@type="ol-events.ch"] oder EntryId
|
race_runner.id aus der EntryList |
| Jahrgang | Person/BirthDate |
YYYY-MM-DD, nur Jahr wird verwendet |
| Geschlecht | Person/@sex |
M oder F
|
| Adresse | Person/Address/* |
Street, ZipCode, City (optional) |
Response:
- 204 No Content — Import wurde gestartet (Verarbeitung erfolgt asynchron)
- 422 Unprocessable Entity — Kodierung fehlt oder ist nicht zugelassen, oder das GZip ist beschädigt
Hinweis: Der Import wird asynchron als Background-Job verarbeitet.
204bestätigt nur den Empfang, Fehler im XML meldet die API nicht mehr. Kontrolliere den Import deshalb auf der öffentlichen Seite des Laufs, siehe Start- und Resultatlisten hochladen.
GET /api/iof/v1/races/{race}/resultlist
Gibt die Resultate eines Laufs zurück, ohne Zwischenzeiten. Team-Mitglieder erscheinen als einzelne Personen. Die Ränge sind neu nach Zeit berechnet, gleiche Zeiten ergeben also nicht denselben Rang.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Response: application/xml — IOF 3.0 ResultList
<?xml version="1.0" encoding="UTF-8"?>
<ResultList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
createTime="2026-03-12T10:00:00+01:00"
creator="ol-events.ch">
<Event>
<Name>Beispiel OL 2026</Name>
</Event>
<ClassResult>
<Class>
<Id>101</Id>
<Name>H20</Name>
</Class>
<PersonResult>
<Person sex="M">
<Id type="IOF">123456</Id>
<Id type="SOLV">AB1CDE</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
<BirthDate>1990-01-01</BirthDate>
</Person>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<Result>
<BibNumber>42</BibNumber>
<StartTime>2026-06-15T10:30:00+02:00</StartTime>
<FinishTime>2026-06-15T11:02:30+02:00</FinishTime>
<Time>1950</Time>
<TimeBehind>0</TimeBehind>
<Position>1</Position>
<Status>OK</Status>
</Result>
</PersonResult>
</ClassResult>
</ResultList>
POST /api/iof/v1/races/{race}/resultlist
Importiert Resultate in einen Lauf. Bestehende Resultate werden wiedererkannt und aktualisiert, siehe Ids und Zuordnung.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
Request:
-
Content-Type:
application/xml -
Body: IOF 3.0
ResultListXML
curl -X POST \
-H "Authorization: Bearer abc123def456..." \
-H "Content-Type: application/xml" \
--data-binary @resultlist.xml \
https://ol-events.ch/api/iof/v1/races/42/resultlist
Erwartetes XML-Format im Request-Body:
<?xml version="1.0" encoding="UTF-8"?>
<ResultList xmlns="http://www.orienteering.org/datastandard/3.0"
iofVersion="3.0"
creator="ZORA">
<Event>
<Name>Beispiel OL 2026</Name>
</Event>
<ClassResult>
<Class>
<Name>H20</Name>
</Class>
<PersonResult>
<EntryId type="ol-events.ch">12345</EntryId>
<Person sex="M">
<Id type="IOF">123456</Id>
<Id type="SOLV">AB1CDE</Id>
<Name>
<Family>Muster</Family>
<Given>Hans</Given>
</Name>
<BirthDate>1990-01-01</BirthDate>
</Person>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<Result>
<BibNumber>42</BibNumber>
<StartTime>2026-06-15T10:30:00+02:00</StartTime>
<FinishTime>2026-06-15T11:02:30+02:00</FinishTime>
<Time>1950.5</Time>
<TimeBehind>0</TimeBehind>
<Position>1</Position>
<Status>OK</Status>
<SplitTime>
<ControlCode>31</ControlCode>
<Time>245</Time>
</SplitTime>
<SplitTime>
<ControlCode>32</ControlCode>
<Time>510</Time>
</SplitTime>
</Result>
</PersonResult>
<TeamResult>
<EntryId type="ol-events.ch">501</EntryId>
<Name>Familie Muster</Name>
<Organisation>
<Name>OLG Beispiel</Name>
</Organisation>
<BibNumber>10</BibNumber>
<TeamMemberResult>
<Person sex="F">
<Name>
<Family>Muster</Family>
<Given>Anna</Given>
</Name>
</Person>
<Result>
<Time>2100.5</Time>
<Status>OK</Status>
<OverallResult>
<Time>2100.5</Time>
<Position>3</Position>
<Status>OK</Status>
</OverallResult>
</Result>
</TeamMemberResult>
</TeamResult>
</ClassResult>
</ResultList>
Importierte Felder pro Resultat:
| Feld | XML-Pfad | Beschreibung |
|---|---|---|
| Nachname | Person/Name/Family |
Pflichtfeld |
| Vorname | Person/Name/Given |
Pflichtfeld |
| Kategorie |
Class/ShortName, sonst Class/Name
|
Zuordnung über das Kürzel; wird bei Bedarf automatisch erstellt |
| Status | Result/Status |
OK, MissingPunch, DidNotFinish, DidNotStart, Disqualified, etc. |
| Gesamtzeit | Result/Time |
In Sekunden, Dezimalstellen erlaubt |
| Rang | Result/Position |
Ganzzahl |
| Rückstand | Result/TimeBehind |
In Sekunden (Dezimal) |
| Startnummer | Result/BibNumber |
Optional |
| Startzeit | Result/StartTime |
ISO 8601 Datetime |
| Zielzeit | Result/FinishTime |
ISO 8601 Datetime |
| Verein | Organisation/Name |
Optional |
| IOF-Nr. | Person/Id[@type="IOF"] |
Siehe Ids und Zuordnung |
| SOLV-Nr. | Person/Id |
Am Format erkannt |
| Unsere Id |
Person/Id[@type="ol-events.ch"] oder EntryId
|
race_runner.id aus der EntryList |
| Jahrgang | Person/BirthDate |
YYYY-MM-DD, nur Jahr wird verwendet |
| Geschlecht | Person/@sex |
M oder F
|
| Adresse | Person/Address/* |
Street, ZipCode, City (optional) |
Zwischenzeiten (SplitTime):
| Feld | XML-Pfad | Beschreibung |
|---|---|---|
| Postencode | SplitTime/ControlCode |
Identifikation des Postens |
| Zeit | SplitTime/Time |
Kumulierte Zeit in Sekunden (Dezimal) |
| Status | SplitTime/@status |
Missing, Additional oder leer (= OK) |
Hinweis: Wenn alle SplitTimes den Status
Missinghaben, werden keine Zwischenzeiten importiert.
Team-Resultate (TeamResult):
TeamResult gilt für Staffeln und für Gruppen und Familien in Einzelläufen. Wie der Import ein Team erkennt, steht unter Ids und Zuordnung.
| Feld | XML-Pfad | Beschreibung |
|---|---|---|
| Zeit | Result/OverallResult/Time |
Ohne OverallResult bleibt die Zeit des Mitglieds leer |
| Rang | Result/OverallResult/Position |
Rang des Teams |
| Rückstand | Result/OverallResult/TimeBehind |
In Sekunden |
| Rang auf der Strecke | Result/Position[@type="Leg"] |
Optional |
| Strecke | Result/Leg |
Bei Staffeln |
In einem Einzellauf zählt ein TeamResult mit genau einem Mitglied und leerem Namen (<Name/>) als Einzelresultat. Dort den Namen deshalb leer lassen, sonst entsteht ein Team mit einer Person. Das gilt auch für TeamStart.
Response:
- 204 No Content — Import wurde gestartet (Verarbeitung erfolgt asynchron)
- 422 Unprocessable Entity — Kodierung fehlt oder ist nicht zugelassen, oder das GZip ist beschädigt
Hinweis: Der Resultat-Import wird asynchron als Background-Job verarbeitet. Bei grossen Resultatdateien kann es einige Sekunden dauern, bis alle Resultate sichtbar sind.
GET /api/xml/v1/races/{race}/radiocontrollist
Gibt die Funkposten pro Kategorie zurück. Das Format ist ein eigenes von ol-events.ch und nicht Teil des IOF Datastandards. Class/Id ist die Id der Kategorie, nicht die Id aus der ClassList.
| Parameter | Typ | Beschreibung |
|---|---|---|
race |
int | Lauf-ID |
<?xml version="1.0" encoding="UTF-8"?>
<RadioControlList apiVersion="1.0" creator="ol-events.ch">
<Class>
<Id type="ol-events">101</Id>
<ShortName>H20</ShortName>
<RadioControls>
<RadioControlStation>
<ControlCode>31</ControlCode>
<PositionOnCourse>3</PositionOnCourse>
</RadioControlStation>
</RadioControls>
</Class>
</RadioControlList>
POST /api/xml/v1/races/{race}/radiocontrollist
Legt Funkposten pro Kategorie an, bestehende bleiben erhalten. Die Kategorie wird über Class/Id[@type="ol-events"] oder Class/ShortName gefunden. Der Body hat dasselbe Format wie die Antwort von GET.
Response:
- 204 No Content — Funkposten wurden importiert
- 422 Unprocessable Entity — Kodierung oder GZip ungültig, oder der Import ist fehlgeschlagen
Typischer Workflow
-
Anmeldungen abrufen:
GET /api/iof/v1/races/{race}/entrylistDen Gesamtstand der gültigen Anmeldungen als IOF EntryList herunterladen. -
Startliste erstellen (in externer Applikation): Startzeiten und Startnummern zuweisen.
-
Startliste hochladen:
POST /api/iof/v1/races/{race}/startlistDie erstellte Startliste zurück an OL-Events.ch senden. -
Wettkampf durchführen und auswerten (in externer Applikation).
-
Resultate hochladen:
POST /api/iof/v1/races/{race}/resultlistDie Resultate als IOF ResultList an OL-Events.ch senden.
HTTP-Statuscodes
| Code | Bedeutung |
|---|---|
| 200 | Erfolgreiche GET-Anfrage, XML im Response-Body |
| 204 | Daten empfangen, bei Start- und Resultatlisten läuft der Import danach im Hintergrund |
| 403 | Ungültiger oder fehlender Bearer Token, oder Token eines anderen Laufs |
| 404 | Lauf nicht gefunden |
| 422 | Kodierung fehlt oder ist nicht zugelassen, oder das GZip ist beschädigt |
| 429 | Mehr als 300 Anfragen pro Minute |
Hinweise
- Die IOF-Dokumente verwenden den IOF Datastandard 3.0 Namespace:
http://www.orienteering.org/datastandard/3.0 - Zugelassen sind genau
encoding="UTF-8",encoding="utf-8"undencoding="windows-1252"in der XML-Deklaration. Der Body darf mit GZip komprimiert sein. - Zeitangaben in
TimeundTimeBehindsind in Sekunden. Dezimalstellen sind erlaubt (z.B.1950.5), angezeigt wird auf ganze Sekunden abgerundet (WO Art. 132 Abs. 2). - Datetime-Felder (
StartTime,FinishTime,createTime) verwenden das ISO 8601 Format. - POST-Endpunkte verarbeiten den Import asynchron. Der Response (204) bestätigt lediglich den Empfang der Daten.
- Kategorien, die im XML vorhanden aber im Lauf nicht angelegt sind, werden beim Import automatisch erstellt.
- Das Kürzel einer Kategorie hat höchstens 12 Zeichen. Längere Namen werden dafür gekürzt, deshalb bei langen Klassennamen
ShortNamemitschicken. - Der Club «-» (Id 1) bedeutet «kein Club».
- Wie Personen und Teams wiedererkannt werden, steht unter Ids und Zuordnung.
Kommentare
0 Kommentare
Zu diesem Beitrag können keine Kommentare hinterlassen werden.