Racepulse

API di export

API pubbliche, di sola lettura, per integrare Racepulse con un applicativo esterno (web o desktop) che deve importare e gestire eventi, intermedi e tempi registrati.

Base URL

https://racepulse.cc/api/export

Autenticazione

Nessuna. Questi endpoint sono pubblici, come il resto dell'app. Sono pensati per dati di gara non sensibili (pettorali e orari di passaggio) — non vengono esposte informazioni personali.

Formati

JSON per integrazioni programmatiche, CSV per import diretto in fogli di calcolo o gestionali.

Endpoint

GET/api/export/events

Elenca gli eventi.

ParametroValoriDefaultDescrizione
archived0 · 101 per ottenere gli eventi archiviati invece di quelli attivi

Risposta 200 — array di eventi:

[
  {
    "id": 12,
    "nome": "Maratona di Prova",
    "creato_il": "2026-08-10T09:00:00.000Z",
    "chiuso": false,
    "archiviato": false,
    "num_intermedi": "3"
  }
]

num_intermedi arriva come stringa (limite del driver Postgres sui valori COUNT) — convertila a numero lato client se ti serve un tipo numerico.

GET/api/export/events/:id

Restituisce un evento completo: anagrafica, intermedi (checkpoint) e tutti i tempi registrati in ciascuno, in un'unica chiamata.

{
  "id": 12,
  "nome": "Maratona di Prova",
  "creato_il": "2026-08-10T09:00:00.000Z",
  "chiuso": false,
  "archiviato": false,
  "intermedi": [
    {
      "id": 30,
      "nome": "10km",
      "ordine": 1,
      "chiuso": false,
      "tempi": [
        {
          "id": 501,
          "sequenza": 1,
          "giorno": 1,
          "orario_ms": 605000,
          "orario": "00:10:05.000",
          "tipo": "atleta",
          "pettorale": "101",
          "nota": null,
          "incerto": false,
          "squalificato": false,
          "nota_squalifica": null
        }
      ]
    }
  ]
}

Campi di un "tempo":

CampoTipoDescrizione
idnumeroid univoco del tempo registrato
sequenzanumeroposizione progressiva (1, 2, 3…), calcolata separatamente per i tempi gun e per tutti gli altri (atleta/custom) nello stesso intermedio
giornonumerogiorno reale in cui il tempo è stato registrato, relativo al primo giorno dell'evento (1 = giorno della primissima scansione, 2 = giorno successivo…). Garantisce l'ordine cronologico corretto anche a cavallo di mezzanotte
orario_msnumeroorario del passaggio, in millisecondi dal riferimento dell'intermedio (gun/orologio)
orariostringalo stesso orario, già formattato HH:MM:SS.mmm
tipostringaatleta (passaggio con pettorale), gun (sparo di partenza), custom (tasto personalizzato)
pettoralestringa · nullnumero pettorale, se applicabile
notastringa · nullnota libera sul passaggio
incertobooleanotempo marcato come incerto dall'operatore
squalificatobooleanoil pettorale è squalificato/DNF su questo passaggio
nota_squalificastringa · nullmotivo della squalifica, se presente

Errori: 404 se l'evento non esiste.

GET/api/export/events/:id/csv

Come sopra, ma come file CSV scaricabile con tutti i tempi dell'evento (tutti gli intermedi in un'unica tabella piatta).

Risposta 200 — Content-Type: text/csv, Content-Disposition: attachment; filename="<nome-evento>.csv"

Colonne: intermedio, sequenza, giorno, orario, millisecondi, tipo, pettorale, nota, incerto, squalificato, nota_squalifica

Errori: 404 se l'evento non esiste.

Esempi

# elenco eventi attivi
curl https://racepulse.cc/api/export/events

# evento completo in JSON
curl https://racepulse.cc/api/export/events/12

# evento completo in CSV, salvato su file
curl -o evento.csv https://racepulse.cc/api/export/events/12/csv
// polling periodico da un'app esterna, per dati "quasi live"
async function pollEvento(eventoId) {
  const res = await fetch(`https://racepulse.cc/api/export/events/${eventoId}`);
  if (!res.ok) throw new Error(`Errore ${res.status}`);
  return res.json();
}

Note per chi consuma questi dati

I dati riflettono lo stato attuale del database: non c'è alcuna cache, ogni chiamata legge dal vivo. Va bene per il polling periodico, ma evita di interrogare più volte al secondo senza motivo.

Un intermedio chiuso non riceve più nuovi tempi, ma quelli già registrati restano interrogabili come sempre.

I campi id (di eventi/intermedi/tempi) sono stabili e possono essere usati come chiave per sincronizzare i dati con un sistema esterno.

Non è previsto alcun webhook/push: l'app esterna deve interrogare gli endpoint quando le servono dati aggiornati.