API per a desenvolupadors

Les mateixes dades que el mapa, en JSON. Gratis, sense registre i sense clau. Fes-la servir al teu web, a la teva app o a la teva recerca.

En un minut

  • Adreça base: https://trenes.valfiguer.com/api/v1
  • Només lectura (GET), respostes en JSON o GeoJSON, en UTF-8 i comprimides si les demanes amb gzip.
  • CORS obert: la pots cridar des del navegador, des de qualsevol domini. No fa servir galetes ni clau.
  • Hores com a marca Unix en segons (*_ts) i com a ISO 8601 en UTC (*_at).
  • Especificació OpenAPI: /api/openapi.json · Consola interactiva: /api/docs
curl -s --compressed https://trenes.valfiguer.com/api/v1/trains | jq '.features | length'

Condicions d'ús

Les dades provenen de Renfe Data, FGC Dades Obertes i Open Data Euskadi (MovEuskadi), totes amb llicència CC BY 4.0. Les pots fer servir per al que vulguis, també amb finalitats comercials, si cites la font. N'hi ha prou amb una línia:

Dades: Renfe Data, FGC i MovEuskadi (CC BY 4.0) via trenes.valfiguer.com

No és un sistema de seguretat. Les posicions arriben amb segons o minuts de retard i hi poden faltar trens. No la facis servir per a decisions de seguretat ni la presentis com a informació oficial; l'oficial és la de cada operador i Adif.

Límits i memòria cau

  • Fins a 30 peticions per segon per IP, amb ràfegues de 100. Per sobre respon 429: espera un segon i torna-ho a provar.
  • Les posicions es renoven cada 15–20 s a l'origen. Demanar /trains més d'un cop cada 5 s no aporta res de nou.
  • Les respostes grans porten ETag: envia If-None-Match i rebràs 304 sense cos si no ha canviat.
  • Si has de moure molt de trànsit o necessites l'històric complet, escriu-nos a info@valfiguer.com.

Com es llegeix un tren

  • delay_s: retard en segons segons l'operador; null si no el publica (FGC només diu si va a l'hora: mira flags).
  • reported_at / age_s: quan es va prendre la posició i la seva antiguitat en generar la resposta. stale: true si fa més de 3 minuts que no s'actualitza.
  • flags: correccions o avisos aplicats a la dada, per exemple una hora corregida o una posició descartada per impossible.
  • category: ld (alta velocitat i llarga distància), md (mitjana distància), cercanias o otros (FGC i Metro Bilbao).

Rutes

Trens en circulació

GET/api/v1/trains

Tots els trens amb posició publicada ara, com a GeoJSON FeatureCollection, amb l'estat de cada font a feeds.

Memòria cau: 5 s, ETag · Prova-ho

{
  "type": "FeatureCollection",
  "generated_at": "2026-11-01T08:12:30Z",
  "generated_ts": 1793520750,
  "attribution": "Fuentes: Renfe Data (data.renfe.com), FGC Dades Obertes … CC BY 4.0. …",
  "feeds": [{ "id": "renfe_ld_positions", "ok": true, "stale": false, "data_age_s": 14 }],
  "features": [{
    "type": "Feature",
    "id": "renfe_ld:<id>",
    "geometry": { "type": "Point", "coordinates": [-3.6893, 40.4066] },
    "properties": {
      "source": "renfe_ld", "operator": "Renfe", "category": "ld",
      "product": "AVE", "train_number": "00297", "nucleo": null,
      "line_color": null, "origin": "Madrid-Puerta de Atocha", "destination": "Barcelona-Sants",
      "status_text": "en", "stop_name": "Zaragoza-Delicias", "platform": "4",
      "delay_s": 180, "reported_at": "2026-11-01T08:12:16Z", "age_s": 14,
      "stale": false, "speed_kmh": 287, "bearing": 64, "flags": []
    }
  }]
}

Un tren

GET/api/v1/trains/{id}

Un tren amb el seu recorregut recent (fins a 80 posicions a track: lon, lat, hora) i el seu itinerari: parades amb hora programada i estimada (horari més el retard actual).

ParàmetreAQuè és
idrutaL'id de /trains, per exemple renfe_cercanias:1004D27203C4a.

Memòria cau: 5 s · Prova-ho

{
  "id": "renfe_ld:00297",
  "properties": { "…": "como en /trains" },
  "track": [[-3.6893, 40.4066, 1793520736]],
  "itinerary": {
    "method": "horario_mas_retraso_actual",
    "delay_s": 180,
    "stops": [{
      "code": "71801", "name": "Barcelona-Sants",
      "arrival_ts": 1793530800, "estimated_arrival_ts": 1793530980,
      "state": "upcoming"
    }]
  }
}

Un tren pel seu número

GET/api/v1/trains/numero/{número}

El mateix que /trains/{id}, cercant pel número comercial que surt al bitllet o al panell. Respon 404 si aquest número ara no té posició.

ParàmetreAQuè és
númerorutaNúmero comercial, amb zeros a l'esquerra o sense.
nucleoconsultaOpcional. Distingeix Cercanías de ciutats diferents: Madrid, Barcelona, València…

Memòria cau: 5 s · Prova-ho

{ "id": "renfe_cercanias:1004D27704C5", "properties": { "…": "…" }, "track": [], "itinerary": null }

Horari d'avui d'un tren

GET/api/v1/horario/numero/{número}

Les sortides d'avui d'un número de tren segons el calendari GTFS de Renfe, amb les seves parades i si està cancel·lat. Serveix per a trens que encara no han sortit.

ParàmetreAQuè és
númerorutaNúmero comercial.
nucleoconsultaOpcional, com a dalt.

Memòria cau: 30 s · Prova-ho

{
  "method": "horario_gtfs",
  "runs": [{
    "trip_id": "0029712026-11-01", "day": "2026-11-01", "cancelled": false,
    "product": "AVE", "origin": "Madrid-Puerta de Atocha", "destination": "Barcelona-Sants",
    "departure_ts": 1793520000, "arrival_ts": 1793530800,
    "itinerary": { "stops": [] }
  }]
}

Tauler d'una estació

GET/api/v1/stations/{código}

Trens de les dues properes hores en una estació: els que circulen, amb hora estimada, i els que encara no han sortit segons l'horari d'avui (state: scheduled). Inclou la fitxa de l'estació quan Adif la publica.

ParàmetreAQuè és
códigorutaCodi d'estació de Renfe (fins a 5 xifres), el mateix de /stations.

Memòria cau: 10 s · Prova-ho

{
  "station": { "code": "18000", "name": "Madrid-Puerta de Atocha", "lat": 40.4066, "lon": -3.6893 },
  "trains": [{
    "id": null, "trip_id": "…", "state": "scheduled", "category": "cercanias",
    "product": "C5", "train_number": "27704", "destination": "Humanes",
    "planned_ts": 1793520660, "estimated_ts": null, "delay_s": null,
    "cancelled": false, "terminates": false
  }]
}

Estacions

GET/api/v1/stations

Totes les estacions amb el seu codi i nom, com a GeoJSON de punts.

Memòria cau: 1 h, ETag · Prova-ho

{ "type": "FeatureCollection", "features": [{ "geometry": { "type": "Point", "coordinates": [-3.6893, 40.4066] }, "properties": { "code": "18000", "name": "Madrid-Puerta de Atocha" } }] }

Línies

GET/api/v1/lines

Recorregut de les línies de Cercanías, FGC i Metro Bilbao amb el seu color oficial, com a GeoJSON de línies simplificades a uns 15 m.

Memòria cau: 1 h, ETag · Prova-ho

{ "type": "FeatureCollection", "features": [{ "properties": { "nucleo": "Madrid", "line": "C5", "name": "Móstoles-El Soto - Humanes", "color": "#FFCB06", "text_color": "#000000" }, "geometry": { "type": "LineString", "coordinates": [] } }] }

Puntualitat

GET/api/v1/puntualidad

Puntualitat diària per línia i producte: viatges, viatges amb retard i suma de retards, a partir de l'últim retard publicat de cada tren.

ParàmetreAQuè és
diasconsultaDies enrere, d'1 a 31 (7 per defecte).

Memòria cau: 5 min · Prova-ho

{ "on_time_threshold_s": 300, "days": [{ "date": "2026-10-31", "partial": false, "groups": [{ "label": "C5", "nucleo": "Madrid", "trips": 412, "on_time": 371, "over_30": 2 }] }] }

Avisos

GET/api/v1/alerts

Avisos actius de Cercanías publicats per Renfe, amb les línies a què afecten.

Memòria cau: 30 s · Prova-ho

{ "alerts": [{ "id": "…", "text": "…", "start": "2026-11-01T05:00:00Z", "end": null, "lines": [{ "nucleo": "Madrid", "line": "C3" }] }] }

Cancel·lacions

GET/api/v1/cancellations

Trens que Renfe dona per cancel·lats ara.

Memòria cau: 30 s · Prova-ho

{ "count": 1, "trains": [{ "trip_id": "…", "category": "md", "product": "MD", "train_number": "18073", "origin": "…", "destination": "…" }] }

Estat

GET/api/v1/status

Resum del servei: nombre de trens, puntualitat del moment i salut de cada font.

Memòria cau: 10 s · Prova-ho

{ "trains": { "total": 812, "fresh": 790, "by_category": { "ld": 120, "cercanias": 610 } }, "delay": { "known": 700, "on_time_share": 0.91 }, "cancelled": 11, "feeds": [{ "id": "renfe_ld_positions", "ok": true, "data_age_s": 14 }] }

Exemples

JavaScript, al navegador o a Node 18+:

const res = await fetch("https://trenes.valfiguer.com/api/v1/trains");
const { features } = await res.json();
const late = features.filter((f) => (f.properties.delay_s ?? 0) > 600);
console.log(`${late.length} trens amb més de 10 min de retard`);

Python:

import httpx

board = httpx.get("https://trenes.valfiguer.com/api/v1/stations/18000").json()
for t in board["trains"][:5]:
    print(t["product"], t["destination"], t["delay_s"])

Mapa amb MapLibre o Leaflet: afegeix la resposta de /trains com a font GeoJSON i refresca-la cada 15 s.

map.addSource("trenes", { type: "geojson", data: "https://trenes.valfiguer.com/api/v1/trains" });
setInterval(() => map.getSource("trenes").setData("https://trenes.valfiguer.com/api/v1/trains"), 15000);

Versions

La v1 és estable: podem afegir camps, però no treure'ls ni canviar-ne el significat sense publicar una v2 i mantenir la v1 almenys sis mesos. El teu codi ha d'ignorar els camps que no conegui.

Més informació sobre les fonts, la seva freqüència i el registre històric a Dades.

Ginys per al teu web

Un tauler de sortides d'una estació o els trens d'una línia, dins la teva pàgina. S'actualitzen sols i ajusten la seva alçada al contingut. Enganxa el bloc on vulguis que aparegui:

<div data-trenes-estacion="18000"></div>
<script src="https://trenes.valfiguer.com/embed.js" async></script>

Una línia: nucli i línia, tal com apareixen al mapa, en minúscules i amb guions.

<div data-trenes-linea="madrid/c5"></div>
<div data-trenes-linea="rodalies-de-catalunya/r2-nord"></div>
<div data-trenes-linea="fgc/s1"></div>
<script src="https://trenes.valfiguer.com/embed.js" async></script>
  • data-tema="claro" (clar) o "oscuro" (fosc): fixa el tema. Sense aquest atribut, segueix el del visitant. L'atribut i els seus valors es mantenen en castellà.
  • data-filas="6": quants trens s'han de mostrar (estació: 1–15, 6 per defecte; línia: 1–20, 8 per defecte).
  • data-idioma="ca": idioma del giny (es, en, ca, eu o gl; castellà per defecte). El tauler i el giny de pantalla d'inici també existeixen en cada idioma: /ca/panel/18000.
  • El codi d'estació és el de Renfe, el mateix de /stations/{código} i de l'adreça de cada pàgina d'estació.
  • Si afegeixes ginys després de carregar la pàgina (una aplicació d'una sola pàgina), crida window.TrenesEmbed.scan().

Sense JavaScript, amb un iframe d'alçada fixa:

<iframe src="https://trenes.valfiguer.com/embed/estacion/18000?tema=claro&filas=5"
        title="Propers trens" loading="lazy"
        style="width:100%;height:360px;border:0"></iframe>

El peu del giny porta l'atribució que demanen les llicències (Renfe Data, FGC i MovEuskadi, CC BY 4.0) i un enllaç a la pàgina completa: no el tapis ni el treguis. Només les rutes /embed/ es poden mostrar dins d'altres webs.

Tauler a pantalla completa

Per a una televisió o una tauleta en un vestíbul, una oficina o una cafeteria: /panel/{código} mostra les properes sortides en gran, amb rellotge, s'actualitza cada 15 s, ajusta la mida de la lletra a la pantalla i, on el navegador ho permet, impedeix que la pantalla s'apagui.

https://trenes.valfiguer.com/panel/18000
https://trenes.valfiguer.com/panel/18000?tema=claro&filas=8

Fosc per defecte; ?tema=claro (clar) per a sales amb molta llum. ?filas= admet de 3 a 20. Cada pàgina d'estació té un enllaç «Mode tauler».

Client JavaScript

Un mòdul petit, sense dependències, per al navegador o Node 18+. Tipus a /sdk/trenes.d.ts.

import { createClient } from "https://trenes.valfiguer.com/sdk/trenes.js";

const api = createClient(); // o createClient({ baseUrl, timeoutMs, fetch })
const { features } = await api.trains();
const board = await api.station("18000"); // null si el codi no existeix
const runs = await api.schedule("00297");
const tren = await api.train(features[0].id);
const lineas = await api.lines();

També exporta cada funció per separat (trains, train, station, schedule, lines…). Un 404 retorna null; qualsevol altre error llança TrenesError amb el seu status. Per a TypeScript, descarrega el .d.ts al costat del mòdul o copia els tipus que necessitis.

Python 3.10+, només amb la biblioteca estàndard:

import json
import urllib.request

BASE = "https://trenes.valfiguer.com/api/v1"

def get(path: str):
    req = urllib.request.Request(BASE + path, headers={"Accept": "application/json"})
    with urllib.request.urlopen(req, timeout=10) as res:
        return json.load(res)

board = get("/stations/18000")
print(board["station"]["name"])
for t in board["trains"][:8]:
    retard = "sense dada" if t["delay_s"] is None else f"{round(t['delay_s'] / 60)} min"
    print(t["product"], t["train_number"], "→", t["destination"], retard)

# Dades: Renfe Data, FGC i MovEuskadi (CC BY 4.0) via trenes.valfiguer.com

Canals RSS

Avisos i cancel·lacions en format RSS, per al teu lector de notícies o per automatitzar alertes. Es poden filtrar per nucli i per línia amb ?nucleo=madrid&linea=c5; cada pàgina de línia enllaça els seus.

Reflecteixen el que Renfe publica a les seves dades obertes, amb les mateixes llacunes. Llicència CC BY 4.0. Els textos dels avisos són en castellà, tal com els publica Renfe.