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.

https://leyes.pisanvs.cl/api/v1OpenAPI 3.1llms.txt

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.

Cabecera
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.

Petición
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.

GET/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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994'
Respuesta
{
  "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º" }
  ]
}
GET/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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994/articulos?q=militante'
Respuesta
{
  "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…"
    }
  ]
}
GET/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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994/articulos/art-1'
Respuesta
{
  "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
}
GET/normas/{idNorma}/versiones

Historial 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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/1984/versiones'
Respuesta
{
  "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.

GET/normas/{idNorma}/diff

Qué 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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994/diff?from=2015-05-05&to=2016-04-15'
Respuesta
{
  "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…" }
      ]
    }
  ]
}
GET/normas/{idNorma}/modificaciones

El 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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994/modificaciones'
Respuesta
{
  "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"
    }
  ]
}
GET/normas/{idNorma}/raw

El 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.
Petición
curl -H "Authorization: Bearer $LEYCHILE_KEY" \
  'https://leyes.pisanvs.cl/api/v1/normas/29994/raw?fecha=2016-04-15'
Respuesta
{
  "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.

Envoltura
{ "error": { "code": "invalid_api_key", "message": "…" } }
400
bad_request

idNorma o fecha mal formada, o falta un parámetro obligatorio.

401
missing_api_key · invalid_api_key

Key ausente, desconocida o revocada.

404
not_found

No existe esa norma, artículo o versión.

503
service_unavailable

Servicio 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.

Petición
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, dfl y dto no tienen equivalente honesto en inglés.
  • Los datos derivan de leychile.cl y se reconstruyen desde un historial git del corpus. /raw enlaza de vuelta a la fuente autoritativa.

Todo esto también está en OpenAPI 3.1, si prefieres generar un cliente. Volver al lector.