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.comNo é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
/trainsmés d'un cop cada 5 s no aporta res de nou. - Les respostes grans porten
ETag: enviaIf-None-Matchi rebràs304sense 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;nullsi no el publica (FGC només diu si va a l'hora: miraflags).reported_at/age_s: quan es va prendre la posició i la seva antiguitat en generar la resposta.stale: truesi 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),cercaniasootros(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àmetre | A | Què és |
|---|---|---|
id | ruta | L'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àmetre | A | Què és |
|---|---|---|
número | ruta | Número comercial, amb zeros a l'esquerra o sense. |
nucleo | consulta | Opcional. 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àmetre | A | Què és |
|---|---|---|
número | ruta | Número comercial. |
nucleo | consulta | Opcional, 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àmetre | A | Què és |
|---|---|---|
código | ruta | Codi 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àmetre | A | Què és |
|---|---|---|
dias | consulta | Dies 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,euogl; 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=8Fosc 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.comCanals 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.
- /api/v1/feeds/avisos.xml: avisos actius de Cercanías i Rodalies.
- /api/v1/feeds/cancelaciones.xml: trens que Renfe marca com a cancel·lats ara.
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.