API · v1
El corpus jurídico chileno, en JSON.
333.026 normas, cada versión histórica de cada una, y el grafo de modificaciones entre ellas. Sólo lectura, autenticada con una API key. Los mismos datos que entrega el servidor MCP — ése devuelve prosa para modelos, ésta devuelve JSON.
Empezar
Autenticación
Todos los endpoints exigen una key. Las emite el operador a mano — pídela. Una key ausente, desconocida o revocada devuelve 401.
Authorization: Bearer lc_live_…De la key sólo se guarda su SHA-256, así que se muestra una única vez al emitirla y después es irrecuperable. Guárdala como cualquier otro secreto.
Lo primero que hay que entender
idNorma es el identificador que sirve
`(tipo, numero)` no identifica una norma chilena. Hay 227 normas que son “DFL 1”, 75 que son “DFL 4” y 525 que son “DTO 1”, de distintos organismos y años. Peor: un idNorma interno puede coincidir con el numero de una ley sin relación — /ley/20780 llegó a resolver a un decreto cuyo idNorma era 20780.
Por eso toda la API direcciona por idNorma, y una búsqueda por cita devuelve todas las candidatas en vez de adivinar. Elige la que querías por su idNorma y organismo, y usa ese idNorma de ahí en adelante.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/search?tipo=dfl&numero=1'Referencia
Endpoints
Ocho, todos GET, todos relativos a https://leyes.pisanvs.cl/api/v1.
/searchBuscar en el corpus
Texto libre con q, o una cita con tipo + numero. Una cita devuelve todas las candidatas, nunca una adivinanza.
qstring- Términos de búsqueda, mínimo 2 caracteres.
tipostring- Tipo de cita: ley, dl, dfl, dto, cod, res…
numerostring- Número de la norma. Requiere
tipo. asOfdate- YYYY-MM-DD. Busca el texto vigente a esa fecha. Por defecto hoy.
limitinteger- 1–100, por defecto 20. Sólo en texto libre: una cita siempre devuelve todo.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/search?q=medio+ambiente&limit=2'{
"query": "medio ambiente",
"asOf": "2026-09-10",
"total": 2,
"resultados": [
{
"idNorma": 30667,
"tipo": "ley",
"numero": "19300",
"titulo": "APRUEBA LEY SOBRE BASES GENERALES DEL MEDIO AMBIENTE",
"organismo": "MINISTERIO SECRETARÍA GENERAL DE LA PRESIDENCIA"
}
]
}/normas/{idNorma}Una norma y su índice de artículos
Metadatos más el índice de artículos. Nunca el texto de los artículos: una norma puede pesar ~350 KB, así que los cuerpos se piden de uno en uno.
idNormaintegerobligatorio- En la ruta. El identificador único de LeyChile.
fechadate- YYYY-MM-DD. Devuelve la versión vigente a esa fecha.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994'{
"idNorma": 29994,
"tipo": "ley",
"numero": "18603",
"titulo": "LEY ORGANICA CONSTITUCIONAL DE LOS PARTIDOS POLITICOS",
"organismo": "MINISTERIO DEL INTERIOR",
"derogado": false,
"fechaPublicacion": "1987-03-23",
"fecha": "2016-04-15",
"totalVersiones": 6,
"articulos": [
{ "slug": "art-1", "label": "articulo 1", "rawHeading": "Artículo 1º" }
]
}/normas/{idNorma}/articulosÍndice de artículos, o buscar dentro de la norma
Sin q, el índice completo a una fecha. Con q, sólo los artículos que coinciden, cada uno con un snippet. Así se ubica el artículo relevante de un código con cientos sin descargar su texto.
idNormaintegerobligatorio- En la ruta.
qstring- Términos a buscar dentro de la norma, mínimo 2 caracteres.
fechadate- YYYY-MM-DD. Por defecto la versión vigente.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994/articulos?q=militante'{
"idNorma": 29994,
"fecha": "2016-04-15",
"query": "militante",
"total": 5,
"articulos": [
{
"slug": "art-23-bis",
"label": "articulo 23 bis",
"rawHeading": "Artículo 23 bis",
"snippet": "…sus <b>militantes</b>. La infracción de esta prohibición…"
}
]
}/normas/{idNorma}/articulos/{slug}El texto de un artículo
Los cuerpos se cortan a 12.000 caracteres. Cuando truncado es true el texto está incompleto y largoCompleto da el largo real — nunca tomes un artículo truncado por el precepto entero.
idNormaintegerobligatorio- En la ruta.
slugstringobligatorio- En la ruta. Del índice de artículos.
fechadate- YYYY-MM-DD. Por defecto la versión vigente.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994/articulos/art-1'{
"idNorma": 29994,
"fecha": "2016-04-15",
"slug": "art-1",
"label": "articulo 1",
"rawHeading": "Artículo 1º",
"body": "Los partidos políticos son asociaciones autónomas y voluntarias…",
"truncado": false,
"largoCompleto": 970
}/normas/{idNorma}/versionesHistorial de versiones
Cada versión con la ventana en que rigió. Los desde son las fechas que se pasan como fecha, from y to en el resto de la API.
idNormaintegerobligatorio- En la ruta.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/1984/versiones'{
"idNorma": 1984,
"vigente": "2025-09-17",
"total": 122,
"versiones": [
{
"desde": "1874-11-12",
"hasta": "1917-09-26",
"causaId": null,
"subject": "Código Penal publicada (1874-11-12)"
}
]
}El Código Penal tiene 122 versiones desde 1874. Ése es el punto del corpus.
/normas/{idNorma}/diffQué cambió entre dos versiones
La pregunta para la que existe este corpus. Devuelve operaciones estructuradas por artículo, no prosa. Una norma que no cambió devuelve 200 con cambios vacío: eso es una respuesta, no un error.
idNormaintegerobligatorio- En la ruta.
fromdateobligatorio- YYYY-MM-DD. La versión anterior.
todateobligatorio- YYYY-MM-DD. La versión posterior.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994/diff?from=2015-05-05&to=2016-04-15'{
"idNorma": 29994,
"from": "2015-05-05",
"to": "2016-04-15",
"resumen": { "modificados": 53, "añadidos": 16, "eliminados": 0 },
"cambios": [
{
"slug": "art-1",
"rawHeading": "Artículo 1º",
"estado": "modificado",
"ops": [
{ "op": "delete", "text": "voluntarias, dotadas de personalidad jurídica…" },
{ "op": "insert", "text": "autónomas y voluntarias organizadas democráticamente…" }
]
}
]
}/normas/{idNorma}/modificacionesEl grafo de modificaciones, en ambos sentidos
Qué normas modificaron a ésta, y a cuáles modificó ella. Cada entrada trae su idNorma, así que nunca hay que resolver una cita ambigua.
idNormaintegerobligatorio- En la ruta.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994/modificaciones'{
"idNorma": 29994,
"modifica": [],
"modificadaPor": [
{
"idNorma": 1089164,
"tipo": "ley",
"numero": "20915",
"titulo": "FORTALECE EL CARÁCTER PÚBLICO Y DEMOCRÁTICO DE LOS PARTIDOS POLÍTICOS…",
"fecha": "2016-04-15"
}
]
}/normas/{idNorma}/rawEl enlace a la fuente autoritativa
Enlaces de vuelta a leychile.cl, para citar o verificar una versión.
idNormaintegerobligatorio- En la ruta.
fechadate- YYYY-MM-DD. Por defecto la versión vigente.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
'https://leyes.pisanvs.cl/api/v1/normas/29994/raw?fecha=2016-04-15'{
"idNorma": 29994,
"fecha": "2016-04-15",
"url": "https://www.leychile.cl/Navegar?idNorma=29994&idVersion=2016-04-15",
"xml": "https://www.leychile.cl/Consulta/obtxml?opt=7&idNorma=29994&idVersion=2016-04-15"
}Comportamiento
Errores
Siempre la misma envoltura, con el código HTTP que corresponde.
{ "error": { "code": "invalid_api_key", "message": "…" } }- 400
bad_requestidNormao fecha mal formada, o falta un parámetro obligatorio.- 401
missing_api_key · invalid_api_keyKey ausente, desconocida o revocada.
- 404
not_foundNo existe esa norma, artículo o versión.
- 503
service_unavailableServicio temporalmente no disponible.
Un arreglo resultados o cambios vacío significa que no hubo coincidencias. Nunca significa que el servicio esté roto: eso siempre es un 4xx o un 5xx.
Las fechas tienen que ser fechas reales del calendario: 2026-02-31 es un 400, no una sustitución silenciosa.
Comportamiento
Caché
Las lecturas de norma, artículo y versiones traen ETag y Cache-Control: private, max-age=300. Devuelve el ETag como If-None-Match y obtienes un 304 sin cuerpo.
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
-H 'If-None-Match: "82b8be35b76e4fdcfa40263691e1b912"' \
'https://leyes.pisanvs.cl/api/v1/normas/29994'private es deliberado: las respuestas van detrás de una cabecera Authorization y no deben quedar en una caché compartida. La búsqueda no se cachea.
Transparencia
Qué se registra
Por cada petición: la API key, la plantilla de ruta, el código HTTP, la duración y la hora.
No se registra: qué buscaste, qué norma o artículo pediste, tu dirección IP, ni tu user agent.
Se guarda la plantilla — /v1/normas/{idNorma} — nunca la ruta concreta. Registrar /v1/normas/29994 construiría un historial de qué leyes lee cada titular de una key, y esta API no lo conserva. Las filas de uso se borran a los 90 días.
El corpus en sí es público y no recoge ninguna dimensión de usuario. La key existe para que el operador vea volumen de llamadas y pueda revocar abusos, no para seguir lecturas.
Antes de integrar
Límites y detalles
- —Hoy no hay límite de tasa ni cuota. Puede cambiar si crece el tráfico, y se avisaría antes. Sé razonable: son 333k normas servidas por una instancia chica.
- —No se envían cabeceras CORS, así que un navegador no puede llamar a esta API entre orígenes. Está pensada para servidor a servidor.
- —Los nombres de campo usan los términos del dominio en español (
titulo,numero,articulos,versiones).norma,dflydtono tienen equivalente honesto en inglés. - —Los datos derivan de leychile.cl y se reconstruyen desde un historial git del corpus.
/rawenlaza de vuelta a la fuente autoritativa.
Todo esto también está en OpenAPI 3.1, si prefieres generar un cliente. Volver al lector.