3XB TävlingsConsult
För utvecklare
Hämta våra resultat, ta emot dem i realtid eller skicka in era egna – för tidtagare, resultatleverantörer och klubbarnas webbplatser.
Vi sköter ofta både tidtagning och resultat, men ibland är vi bara ena halvan: någon annan tar tiden och vi visar resultatet, eller tvärtom. Då ska kopplingen mellan oss vara den enkla delen av tävlingen. Allt går över ett öppet JSON-API med samma format oavsett gren.
Kopiera till LLM
Bygger ni med en AI-assistent? Kopiera hela integrationsguiden – endpoints, autentisering, payloads, webhooks och exempel – som Markdown, klistra in den och be assistenten skriva integrationen.
Tre sätt att integrera
Välj det som passar er del av tävlingen. Sätten går att kombinera.
- HämtaNi visar resultat som vi tar tid påLäs tävlingar, klasser, deltagare, startlistor och resultattabellen med vanliga GET-anrop. Resultatet kommer färdigräknat, med placeringar, klassplaceringar, gap och poäng enligt tävlingens värderingsregel.Läsnyckel
- Ta emotNi vill ha varje ändring direktVi POSTar till er https-adress varje gång en start-, mål- eller mellantid registreras (timing-event) och varje gång resultattabellen ändras (results). Leveranserna är signerade med HMAC-SHA256 och görs om tills ni svarat – ni missar inget för att er server startade om.Ingen nyckel – en mottagaradress
- Skicka inNi tar tid, vi visar resultatenPublicera tävling, klasser och deltagare med era egna ID:n, och skicka antingen passeringar – vi räknar ihop start och mål – eller färdiga sträckresultat med tid, status och varv. Vi visar resultatet live och skickar det vidare till andras webhooks.Skrivnyckel
Kom igång
- 1
Be om en nyckel
Berätta vilken tävling det gäller och om ni ska hämta eller skicka in data, så skapar vi en läs- eller skrivnyckel. Vill ni börja med att prova kan ni få en sandlådenyckel till demotävlingen ”DEMO – Integrationssandlåda”, som är förifylld med klasser, deltagare och resultat.
- 2
Testa i webbläsaren
Öppna API-referensen, klistra in nyckeln och skicka riktiga anrop med knappen ”Test Request”. Inget eget verktyg behövs.
- 3
Hämta resultatet
Lista tävlingarna nyckeln når och hämta resultattabellen för den ni vill visa. Uppdatera vid behov, eller låt en webhook tala om när något ändrats.
- 4
Koppla en webhook (valfritt)
Ge oss en https-adress som tar emot POST. Vi registrerar den, väljer vilka händelser den ska få och om den gäller en tävling eller alla, och ger er signeringshemligheten en gång. Vi kan skicka en testleverans direkt.
Hämta resultat
Alla anrop går mot en bas-URL och bär nyckeln i headern X-API-KEY.
- Bas-URL
- https://api.tavlingsconsult.com/api/integration/v1
curl "https://api.tavlingsconsult.com/api/integration/v1/competitions/12/results" \
-H "X-API-KEY: tc_live_din_nyckel"{
"competitionId": 12,
"competitionName": "Midnattsloppet 2026",
"ratingRule": "Default",
"heats": [1, 2],
"entries": [
{
"position": 1,
"classPosition": 1,
"startNumber": 5,
"name": "Erik Svensson",
"className": "Open",
"totalTime": 185420,
"gapToLeader": 0,
"heatResults": [
{ "heatNumber": 1, "timeMs": 92710, "penalty": 0, "status": 0 },
{ "heatNumber": 2, "timeMs": 92710, "penalty": 0, "status": 0 }
]
}
]
}Samma nyckel når också /competitions, /competitions/{id}/competitors, /competitions/{id}/start-list och tidtagningens rålogg. Kvalpoäng, varv och delade placeringar läggs till i svaret bara för tävlingar som använder dem.
Ta emot webhooks
Vi skickar, ni svarar 2xx. Inget att fråga efter.
POST /er-adress
Content-Type: application/json
X-TavlingsConsult-Event: results
X-TavlingsConsult-Delivery: 3f1c2a9e-8b7d-4c51-9a0e-2d6f4b8c1e07
X-TavlingsConsult-Attempt: 1
X-TavlingsConsult-Timestamp: 1700000000
X-TavlingsConsult-Signature: sha256=<hex>
{
"id": "3f1c2a9e-8b7d-4c51-9a0e-2d6f4b8c1e07",
"event": "results",
"competitionId": 12,
"sentAtUtc": "2026-07-15T18:22:05.123Z",
"data": { "...": "samma format som GET /competitions/{id}/results" }
}Signaturen är HMAC-SHA256 över {timestamp}.{body} med er signeringshemlighet, i gemena hex-tecken. Räkna den på kroppen exakt som den kom, innan ni tolkar JSON, och jämför i konstant tid.
app.MapPost("/tavlingsconsult", async (HttpRequest request) =>
{
using var reader = new StreamReader(request.Body);
var body = await reader.ReadToEndAsync();
var timestamp = request.Headers["X-TavlingsConsult-Timestamp"].ToString();
var signature = request.Headers["X-TavlingsConsult-Signature"].ToString();
if (!long.TryParse(timestamp, out var seconds) ||
Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - seconds) > 300)
return Results.Unauthorized();
var hash = HMACSHA256.HashData(
Encoding.UTF8.GetBytes(secret),
Encoding.UTF8.GetBytes($"{timestamp}.{body}"));
var expected = "sha256=" + Convert.ToHexStringLower(hash);
if (!CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signature)))
return Results.Unauthorized();
// Tolka body som JSON först nu: id, event, competitionId, data.
// Har ni redan tagit emot samma id är det ett omförsök – svara 2xx igen.
return Results.NoContent();
});Skicka in tider och resultat
För er som tar tiden och vill att vi visar resultatet.
Med en skrivnyckel publicerar ni tävlingen, klasserna och deltagarna med era egna ID:n – samma anrop igen uppdaterar i stället för att skapa dubbletter. Därefter skickar ni det ni har: passeringar löpande, eller färdiga sträckresultat i en batch. Sträckan skapas automatiskt första gången något kommer in på den.
curl -X POST "https://api.tavlingsconsult.com/api/integration/v1/results" \
-H "X-API-KEY: tc_live_din_skrivnyckel" \
-H "Content-Type: application/json" \
-d '{
"competitionExternalId": 1001,
"heatNumber": 2,
"results": [
{ "startNumber": 5, "status": 0, "timeMs": 92710 },
{ "startNumber": 7, "status": 0, "timeMs": 93100, "penaltyMs": 10000 },
{ "startNumber": 9, "status": 2 }
]
}'Varje rad är hela resultatet: status 0 kräver en tid, ett utelämnat tillägg är noll, och ett utelämnat varvantal lämnar det vi har orört. Levererar ni till en av våra tävlingar går samma sak mot POST /heats/{heatId}/results.
curl -X POST "https://api.tavlingsconsult.com/api/integration/v1/timing-events" \
-H "X-API-KEY: tc_live_din_skrivnyckel" \
-H "Content-Type: application/json" \
-d '{
"competitionExternalId": 1001,
"heatNumber": 1,
"type": "RallyFinish",
"startNumber": 5,
"timestampMs": 1750000092710
}'Bra att veta
- Alla tider är i millisekunder. Skicka
timestampMssom Unix-ms – vi lagrar och levererar det som millisekunder sedan midnatt i svensk tid. - Status per sträcka:
0OK,1DNS,2DNF,3DSQ. - Placeringen avgörs av tävlingens
ratingRule– summerad tid, bästa sträcka, kvalpoäng eller varv. Visa våra placeringar i stället för att räkna om dem. - Webhooks går bara till https, följer inga omdirigeringar och väntar högst 10 sekunder på ett
2xx-svar. - En leverans som inte får
2xxgörs om – åtta försök över drygt 20 timmar – med sammaidoch samma kropp. Sparaidoch hoppa över dubbletter. results-händelsen bär alltid hela tabellen, inte bara ändringen, och en nyare lista ersätter en äldre som väntar på omförsök. Hela läget finns dessutom alltid iGET /competitions/{id}/results.- Färdiga resultat skickas i batch, upp till 1000 rader per anrop, och prövas i sin helhet: en felaktig rad avvisar allt och svaret listar varje fel. Samma anrop igen ger inga dubbletter.
Allt detta – och resten – står i API-referensen och i integrationsguiden ovan.
Behöver ni en nyckel?
Skriv vilken tävling det gäller, vilket system ni har och om ni ska hämta, ta emot eller skicka in data. Vi svarar med en nyckel eller en sandlådenyckel att börja med.
Är du arrangör och inte utvecklare? Läs mer för arrangörer.