{"openapi":"3.1.0","info":{"title":"Datos México — API del observatorio","version":"2.0.0","description":"\nAPI pública del Observatorio Datos México.\n\nCada base de datos expuesta declara su fuente oficial, la edición o corte\nmás reciente que contiene y las verificaciones que se le hicieron contra la\npublicación original. Lo que no está aquí, no lo tenemos: el catálogo dice\nqué sí y qué no.\n\n**Principios.** Las bases oficiales son de solo lectura: ninguna operación de\nesta API modifica un dato publicado; cada carga es un script versionado que se\nverifica contra la publicación original. Un posible error se reporta en\n**Erratas** (registro público con autoría, revisión y edición en que se\ncorrigió). Los métodos de escritura existen solo donde son correctos: erratas,\nla tabla pedagógica del curso de Bases de Datos y las operaciones de\nrecálculo de tablas derivadas, todos con autenticación.\n\n**Observatorio hecho por estudiantes, egresados y colaboradores del ITAM.**\nSitio: [datosmexico.org](https://datosmexico.org) · Modelo institucional:\n[datosmexico.org/modelo](https://datosmexico.org/modelo).\n","contact":{"name":"Observatorio Datos México","url":"https://datosmexico.org","email":"equipo@datosmexico.org"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"},"termsOfService":"https://datosmexico.org/privacidad"},"externalDocs":{"description":"Modelo institucional del observatorio","url":"https://datosmexico.org/modelo"},"servers":[{"url":"https://api.datosmexico.org","description":"Producción"}],"tags":[{"name":"consar","description":"CONSAR — Sistema de Ahorro para el Retiro: recursos, comisiones, flujos, traspasos, activo neto, rendimientos, cuentas y precios de las SIEFOREs. Fuente: CONSAR vía datos.gob.mx."},{"name":"enigh","description":"ENIGH 2024 Nueva Serie — microdatos completos y agregados que reproducen el comunicado oficial. Fuente: INEGI."},{"name":"comparativo","description":"Cruces entre el padrón de servidores públicos de la CDMX y la ENIGH."},{"name":"servidores","description":"Padrón de remuneraciones de servidores públicos de la Ciudad de México: búsqueda y estadísticas. Solo lectura."},{"name":"sectores","description":"Sectores del padrón CDMX: lista, estadísticas y comparación."},{"name":"catalogos","description":"Catálogos del padrón CDMX (sexos, puestos, contratación, personal, nómina, universos, sectores, niveles salariales). Solo lectura."},{"name":"dashboard","description":"Tablero del padrón CDMX a partir de tablas derivadas (mv_dashboard_*)."},{"name":"analytics","description":"Rankings y brechas del padrón CDMX."},{"name":"personas","description":"Personas del padrón CDMX. Solo lectura: las correcciones se reportan en Erratas."},{"name":"nombramientos","description":"Nombramientos del padrón CDMX. Solo lectura: las correcciones se reportan en Erratas."},{"name":"export","description":"Exportación CSV del padrón CDMX."},{"name":"enoe","description":"ENOE 15+ — indicadores laborales trimestrales por entidad y microdatos completos (101.5 millones de filas). Fuente: INEGI."},{"name":"inegi","description":"Banco de Indicadores del INEGI completo: 31,817 indicadores a nivel nacional, estatal y municipal, al día con la última actualización publicada."},{"name":"inegi-datos-abiertos","description":"Todos los microdatos y tabulados de la descarga masiva del INEGI: microdatos en Parquet con tipado riguroso y el zip original conservado, tabulados archivados íntegros, todo con manifiesto (SHA-256, filas, esquema) y avance medible contra el inventario oficial."},{"name":"clasificadores","description":"Catálogos y clasificadores del INEGI: SCIAN 2023/2018/2013 con productos, SINCO 2019/2011, CMO histórica y el Catálogo Único de Claves de Áreas Geoestadísticas (32 entidades, 2,478 municipios, 296,633 localidades con coordenadas). Cada uno verificado contra los conteos publicados por el INEGI."},{"name":"denue","description":"DENUE — las 6,138,075 unidades económicas del país con sus 42 campos (edición 05/2026) y las 25 ediciones históricas 2010-2026 por edición, entidad, municipio, clase y estrato. Fuente: INEGI."},{"name":"censo2020","description":"Censo de Población y Vivienda 2020 — 286 indicadores por localidad, municipio y entidad (ITER); AGEB y manzana en archivos Parquet. Fuente: INEGI."},{"name":"anuies","description":"Anuario Estadístico de Educación Superior (ANUIES) completo: todas las instituciones del país, 2000-2001 a 2025-2026, programa por programa (matrícula, nuevo ingreso, egresados, lugares, titulados y solicitudes por sexo, edad, discapacidad, lengua indígena y procedencia). Fuente: anuario.anuies.mx."},{"name":"unam","description":"Todo lo que tenemos de la UNAM: el Concurso de Selección a licenciatura (distribución de aciertos por carrera-plantel, encabezados oficiales, universo, cobertura, cronología; dataset del observatorio, CC BY 4.0) y la UNAM en el Anuario ANUIES ciclo por ciclo."},{"name":"cubos","description":"Cubos del explorador del observatorio (datosmexico.org/observatorio): una capa uniforme de medidas y dimensiones sobre las bases del catálogo, con consulta agregada en JSON o CSV y una URL que reproduce cada tabla."},{"name":"catalogo","description":"Qué bases tenemos, hasta cuándo llegan, con qué se verificaron y su esquema. Lo que no está aquí, no lo tenemos."},{"name":"clima","description":"Clima actual de las 32 capitales estatales, custodiado por el observatorio desde Open-Meteo (fuente de 15 minutos; refresco cada 5) y reportado al pulso del Protocolo DPM como el dato datos-mexico/clima-capitales."},{"name":"sismos","description":"Sismos recientes del Servicio Sismológico Nacional (UNAM), leídos del canal RSS una vez por minuto con la latencia medida entre el origen y su publicación: la sonda del Protocolo DPM para saber si México tiene un dato público que llegue en segundos."},{"name":"dpm","description":"El pulso del Protocolo DPM · Datos Por Minuto (github.com/Datos-Mexico/datos-mexico-dpm): los sistemas adheridos reportan resúmenes por minuto, ingestas y usuarios por día; el pulso calcula por reloj la clase de cada dato (DPM, DPS, DPMS o fuera de clase), el caudal y los usuarios DPM diarios, y sirve la insignia viva. Ninguna cifra del protocolo se enuncia en público si no la produjo el pulso."},{"name":"erratas","description":"Registro público de posibles errores en datos oficiales: quién lo reportó, qué se observó, qué se propone, revisión y edición en que se corrigió. El dato publicado nunca cambia por esta vía."},{"name":"auth","description":"Autenticación OAuth2 (password flow → JWT). Las cuentas las provisiona el observatorio; el registro público está deshabilitado."},{"name":"admin","description":"Operación: recálculo de tablas derivadas a partir de las oficiales. Solo administradores."},{"name":"demo","description":"Demo del curso de Bases de Datos (ITAM, sección 001): tabla pedagógica, no oficial."},{"name":"demo-admin","description":"Administración de la tabla del curso. Solo administradores."}],"components":{"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"tokenUrl":"/api/v1/auth/token","scopes":{}}}},"LlaveDPM":{"type":"http","scheme":"bearer","description":"Llave de reporte del sistema adherido; la emite un administrador del observatorio."}},"schemas":{},"parameters":{}},"paths":{"/health":{"get":{"tags":["Sistema"],"summary":"Estado del servicio","description":"Responde si la API está viva y qué versión corre.","operationId":"get_Salud","responses":{"200":{"description":"Servicio operando","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"version":{"type":"string"},"hora_utc":{"type":"string"}},"required":["status","version","hora_utc"]}}}}}}},"/api/v1/catalogo/datasets":{"get":{"tags":["catalogo"],"operationId":"catalogo_datasets","summary":"Qué datos tenemos y hasta cuándo","description":"Catálogo vivo de las bases de datos del observatorio: fuente, licencia, periodicidad, corte más reciente contenido, tablas con su número de filas y columnas, y el prefijo de la API donde se consultan. Las cifras se leen de las bases en el momento (con caché de 10 minutos). Lo que no aparece aquí, no lo tenemos.","responses":{"200":{"description":"Catálogo de bases de datos.","content":{"application/json":{"schema":{"type":"object","properties":{"generado":{"type":"string"},"n_datasets":{"type":"integer"},"datasets":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"fuente_url":{"type":"string"},"licencia":{"type":"string"},"descripcion":{"type":"string"},"periodicidad":{"type":"string"},"corte":{"type":["string","null"]},"unidad_corte":{"type":"string"},"prefijo_api":{"type":"string"},"n_tablas":{"type":"integer"},"n_filas":{"type":"integer"},"tablas":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"filas":{"type":"integer"},"columnas":{"type":"integer"}},"required":["nombre","filas","columnas"]}},"notas":{"type":"array","items":{"type":"string"}},"esquema_url":{"type":"string"}},"required":["clave","nombre","fuente","fuente_url","licencia","descripcion","periodicidad","corte","unidad_corte","prefijo_api","n_tablas","n_filas","tablas","notas","esquema_url"]}}},"required":["generado","n_datasets","datasets"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogo/datasets/{dataset}/esquema":{"get":{"tags":["catalogo"],"operationId":"catalogo_esquema","summary":"Esquema de una base: tablas, columnas y relaciones","description":"Esquema legible por máquina de una base del observatorio: cada tabla con sus columnas (tipo, nulabilidad, llave primaria) y las relaciones (llaves foráneas) entre tablas. Es la fuente para dibujar el diagrama de relaciones.","parameters":[{"schema":{"type":"string"},"required":true,"name":"dataset","in":"path"}],"responses":{"200":{"description":"Esquema de la base.","content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"n_tablas":{"type":"integer"},"tablas":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"filas":{"type":"integer"},"columnas":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"tipo":{"type":"string"},"nulo":{"type":"boolean"},"llave_primaria":{"type":"boolean"}},"required":["nombre","tipo","nulo","llave_primaria"]}},"llave_primaria":{"type":"array","items":{"type":"string"}}},"required":["nombre","filas","columnas","llave_primaria"]}},"relaciones":{"type":"array","items":{"type":"object","properties":{"desde_tabla":{"type":"string"},"desde_columna":{"type":"string"},"hacia_tabla":{"type":"string"},"hacia_columna":{"type":"string"}},"required":["desde_tabla","desde_columna","hacia_tabla","hacia_columna"]}}},"required":["clave","nombre","n_tablas","tablas","relaciones"]}}}},"404":{"description":"Base inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/cubos":{"get":{"tags":["cubos"],"operationId":"cubos_catalogo","summary":"Qué cubos se pueden explorar","description":"Catálogo de los cubos del explorador del observatorio, agrupados por tema. Un cubo es una tabla consultable con medidas (columnas numéricas que se agregan) y dimensiones (columnas por las que se agrupa y filtra). Cada cubo trae la URL de su ficha (diccionario) y la de su consulta predeterminada.","responses":{"200":{"description":"Catálogo.","content":{"application/json":{"schema":{"type":"object","properties":{"n_temas":{"type":"integer"},"n_cubos":{"type":"integer"},"como_consultar":{"type":"string"},"temas":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"descripcion":{"type":"string"},"cubos":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"tema":{"type":"string"},"descripcion":{"type":"string"},"fuente":{"type":"string"},"fuente_url":{"type":"string"},"licencia":{"type":"string"},"n_medidas":{"type":"integer"},"n_dimensiones":{"type":"integer"},"ficha_url":{"type":"string"},"datos_url":{"type":"string"}},"required":["clave","nombre","tema","descripcion","fuente","fuente_url","licencia","n_medidas","n_dimensiones","ficha_url","datos_url"]}}},"required":["clave","nombre","descripcion","cubos"]}}},"required":["n_temas","n_cubos","como_consultar","temas"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/cubos/{cubo}":{"get":{"tags":["cubos"],"operationId":"cubo_ficha","summary":"Ficha (diccionario) de un cubo","description":"Medidas con unidad y si son sumables, dimensiones con tipo (categórica, temporal, geográfica), jerarquía (padre) y si son virtuales (sus miembros son columnas de una tabla ancha), filas del universo, corte más reciente, consulta predeterminada, notas de método y fuente.","parameters":[{"schema":{"type":"string"},"required":true,"name":"cubo","in":"path"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"tema":{"type":"string"},"descripcion":{"type":"string"},"fuente":{"type":"string"},"fuente_url":{"type":"string"},"licencia":{"type":"string"},"n_medidas":{"type":"integer"},"n_dimensiones":{"type":"integer"},"ficha_url":{"type":"string"},"datos_url":{"type":"string"},"filas":{"type":"integer"},"corte":{"type":["string","null"]},"medidas":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"titulo":{"type":"string"},"unidad":{"type":["string","null"]},"sumable":{"type":"boolean"},"decimales":{"type":["integer","null"]},"descripcion":{"type":["string","null"]}},"required":["clave","titulo","unidad","sumable","decimales","descripcion"]}},"dimensiones":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"titulo":{"type":"string"},"tipo":{"type":"string","enum":["categorica","temporal","geografica"]},"geo":{"type":["string","null"]},"padre":{"type":["string","null"]},"virtual":{"type":"boolean"},"con_nombre":{"type":"boolean"},"filtro_obligatorio":{"type":"boolean"},"descripcion":{"type":["string","null"]}},"required":["clave","titulo","tipo","geo","padre","virtual","con_nombre","filtro_obligatorio","descripcion"]}},"predeterminado":{"type":"object","properties":{"medidas":{"type":"array","items":{"type":"string"}},"columnas":{"type":"array","items":{"type":"string"}},"filtros":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["medidas","columnas","filtros"]},"notas":{"type":"array","items":{"type":"string"}},"api_dominio":{"type":"string"},"miembros_url":{"type":"string"},"como_consultar":{"type":"string"}},"required":["clave","nombre","tema","descripcion","fuente","fuente_url","licencia","n_medidas","n_dimensiones","ficha_url","datos_url","filas","corte","medidas","dimensiones","predeterminado","notas","api_dominio","miembros_url","como_consultar"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/cubos/{cubo}/miembros":{"get":{"tags":["cubos"],"operationId":"cubo_miembros","summary":"Miembros de una dimensión","description":"Los valores que toma una dimensión (identificador, nombre y filas), ordenados como en la fuente. `q` busca por contenido en el nombre o el identificador; los filtros `f.<dimensión>` de otras dimensiones acotan la lista (por ejemplo, las escuelas de una institución). Tope: 5,000 miembros por llamada.","parameters":[{"schema":{"type":"string"},"required":true,"name":"cubo","in":"path"},{"schema":{"type":"string"},"required":true,"name":"dimension","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000},"required":false,"name":"limite","in":"query"}],"responses":{"200":{"description":"Miembros.","content":{"application/json":{"schema":{"type":"object","properties":{"cubo":{"type":"string"},"dimension":{"type":"string"},"n":{"type":"integer"},"limitado":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"n":{"type":["integer","null"]}},"required":["id","nombre","n"]}}},"required":["cubo","dimension","n","limitado","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/cubos/{cubo}/datos":{"get":{"tags":["cubos"],"operationId":"cubo_datos","summary":"Consultar un cubo (tabla agregada)","description":"La consulta del explorador: agrega las medidas por las columnas (dimensiones) pedidas, con filtros, orden y límite. GET /api/v1/cubos/{cubo}/datos?medidas=a,b&columnas=x,y&f.x=v1|v2&padres=1&orden=a&sentido=desc&limite=50&formato=jsonrecords|jsonarrays|csv. Las medidas y columnas se separan con coma; cada filtro es un parámetro f.<dimensión> cuyos valores (identificadores de miembro, ver /miembros) se separan con |. Sin `limite` se devuelven hasta 50,000 filas y `limitado` avisa si faltaron. Con `padres=1` cada columna trae antes sus niveles superiores en la jerarquía. Las dimensiones con nombre devuelven dos columnas (`<dimensión>_id` y `<dimensión>`); las geográficas con clave INEGI distinta del identificador agregan `<dimensión>_cve`. `formato=csv` descarga el archivo; `jsonarrays` devuelve las filas como arreglos en el orden de `columnas`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"cubo","in":"path"},{"schema":{"type":"string"},"required":true,"name":"medidas","in":"query"},{"schema":{"type":"string"},"required":false,"name":"columnas","in":"query"},{"schema":{"type":"string"},"required":false,"name":"padres","in":"query"},{"schema":{"type":"string"},"required":false,"name":"orden","in":"query"},{"schema":{"type":"string","enum":["asc","desc"]},"required":false,"name":"sentido","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50000},"required":false,"name":"limite","in":"query"},{"schema":{"type":"string","enum":["jsonrecords","jsonarrays","csv"]},"required":false,"name":"formato","in":"query"}],"responses":{"200":{"description":"Resultado.","content":{"application/json":{"schema":{"type":"object","properties":{"cubo":{"type":"string"},"consulta":{"type":"object","properties":{"medidas":{"type":"array","items":{"type":"string"}},"columnas":{"type":"array","items":{"type":"string"}},"filtros":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"padres":{"type":"boolean"},"orden":{"type":["string","null"]},"sentido":{"type":"string"},"limite":{"type":"integer"}},"required":["medidas","columnas","filtros","padres","orden","sentido","limite"]},"columnas":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"titulo":{"type":"string"},"tipo":{"type":"string","enum":["id","dimension","geo","medida"]},"dimension":{"type":"string"},"unidad":{"type":"string"},"sumable":{"type":"boolean"}},"required":["clave","titulo","tipo"]}},"filas":{"type":"array","items":{"anyOf":[{"type":"object","additionalProperties":{}},{"type":"array","items":{}}]}},"n":{"type":"integer"},"limitado":{"type":"boolean"},"ms":{"type":"integer"},"fuente":{"type":"string"},"csv_url":{"type":"string"}},"required":["cubo","consulta","columnas","filas","n","limitado","ms","fuente","csv_url"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"504":{"description":"La consulta excedió la capacidad de la base: reduzca columnas o agregue filtros.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"200 (csv)":{"description":"CSV con BOM (formato=csv).","content":{"text/csv":{"schema":{"type":"string"}}}}}}},"/api/v1/consar/afores":{"get":{"tags":["consar"],"operationId":"get_afores_api_v1_consar_afores_get","summary":"Catálogo de las 11 AFOREs","description":"Lista todas las AFOREs del sistema mexicano de ahorro para el retiro, ordenadas por tamaño (recursos registrados en SAR a 2025-06-01). Incluye fecha_alta_serie (primer mes con datos no-nulos en el CSV oficial).","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"afores":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"nombre_csv":{"type":"string"},"tipo_pension":{"type":"string"},"fecha_alta_serie":{"type":"string"},"activa":{"type":"boolean"},"orden_display":{"type":"integer"}},"required":["id","codigo","nombre_corto","nombre_csv","tipo_pension","fecha_alta_serie","activa","orden_display"]}},"source":{"type":"string"}},"required":["count","afores","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/tipos-recurso":{"get":{"tags":["consar"],"operationId":"get_tipos_recurso_api_v1_consar_tipos_recurso_get","summary":"Catálogo de los 15 conceptos de recurso","description":"Lista los 15 tipos de recurso reportados mensualmente por CONSAR. Categoría: component (atómico), aggregate (suma de components), total (agregado AFORE/sistema), operativo (capital propio de la AFORE).","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"tipos_recurso":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"codigo":{"type":"string"},"columna_csv":{"type":"string"},"nombre_corto":{"type":"string"},"nombre_oficial":{"type":"string"},"descripcion":{"type":["string","null"]},"categoria":{"type":"string"},"es_total_sar":{"type":"boolean"},"orden_display":{"type":"integer"}},"required":["id","codigo","columna_csv","nombre_corto","nombre_oficial","descripcion","categoria","es_total_sar","orden_display"]}}},"required":["count","tipos_recurso"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/totales":{"get":{"tags":["consar"],"operationId":"get_totales_api_v1_consar_recursos_totales_get","summary":"Serie temporal: recursos totales registrados en el SAR (nacional)","description":"Retorna los 326 puntos mensuales de la serie de recursos totales registrados en el SAR a nivel sistema (suma sobre todas las AFOREs). Cobertura 1998-05-01 a 2025-06-01.","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"unit":{"type":"string"},"n_puntos":{"type":"integer"},"fecha_min":{"type":"string"},"fecha_max":{"type":"string"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"monto_mxn_mm":{"type":"number"},"n_afores":{"type":"integer"}},"required":["fecha","monto_mxn_mm","n_afores"]}},"caveats":{"type":"array","items":{"type":"string"}},"source":{"type":"string"}},"required":["unit","n_puntos","fecha_min","fecha_max","serie","caveats","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/por-afore":{"get":{"tags":["consar"],"operationId":"get_por_afore_api_v1_consar_recursos_por_afore_get","summary":"Snapshot mensual: recursos por AFORE en una fecha específica","description":"Retorna para la fecha indicada (YYYY-MM o YYYY-MM-01) los recursos totales SAR, recursos de los trabajadores y recursos administrados por cada una de las 11 AFOREs. Incluye % del sistema.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (ej. 2025-06 o 2025-06-01)"},"required":true,"description":"YYYY-MM o YYYY-MM-01 (ej. 2025-06 o 2025-06-01)","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"total_sistema_mm":{"type":"number"},"n_afores_reportando":{"type":"integer"},"afores":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"sar_total_mm":{"type":["number","null"]},"recursos_trabajadores_mm":{"type":["number","null"]},"recursos_administrados_mm":{"type":["number","null"]},"pct_sistema":{"type":["number","null"]}},"required":["afore_codigo","afore_nombre_corto","sar_total_mm","recursos_trabajadores_mm","recursos_administrados_mm","pct_sistema"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","unit","total_sistema_mm","n_afores_reportando","afores","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/por-componente":{"get":{"tags":["consar"],"operationId":"get_por_componente_api_v1_consar_recursos_por_componente_get","summary":"Snapshot mensual: desglose por tipo de recurso (nacional)","description":"Retorna para la fecha indicada (YYYY-MM) el monto agregado a nivel sistema para cada uno de los 15 tipos de recurso. Incluye % respecto al sar_total donde sea informativo (components y aggregates).","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"sar_total_mm":{"type":"number"},"n_componentes":{"type":"integer"},"componentes":{"type":"array","items":{"type":"object","properties":{"tipo_codigo":{"type":"string"},"tipo_nombre_corto":{"type":"string"},"categoria":{"type":"string"},"monto_mxn_mm":{"type":"number"},"pct_del_sar_total":{"type":["number","null"]}},"required":["tipo_codigo","tipo_nombre_corto","categoria","monto_mxn_mm","pct_del_sar_total"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","unit","sar_total_mm","n_componentes","componentes","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/imss-vs-issste":{"get":{"tags":["consar"],"operationId":"get_imss_vs_issste_api_v1_consar_recursos_imss_vs_issste_get","summary":"Serie temporal: RCV-IMSS vs RCV-ISSSTE (privado vs público)","description":"Retorna la serie mensual agregada a nivel sistema de RCV-IMSS (trabajadores del sector privado afiliados al IMSS) y RCV-ISSSTE (trabajadores del sector público). RCV-ISSSTE reportado desde ~2008 con la reforma ISSSTE.","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"unit":{"type":"string"},"n_puntos":{"type":"integer"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"rcv_imss_mm":{"type":["number","null"]},"rcv_issste_mm":{"type":["number","null"]},"ratio_issste_sobre_imss":{"type":["number","null"]}},"required":["fecha","rcv_imss_mm","rcv_issste_mm","ratio_issste_sobre_imss"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["unit","n_puntos","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/composicion":{"get":{"tags":["consar"],"operationId":"get_composicion_api_v1_consar_recursos_composicion_get","summary":"Desglose contable del SAR: 8 componentes vs total reportado","description":"Para la fecha indicada, retorna los 8 componentes de la identidad sar_total (verificada empíricamente al peso en 98.83% de filas y 100% de filas 2020+). Incluye delta vs total reportado para transparencia sobre el residuo histórico.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"sar_total_reportado_mm":{"type":"number"},"suma_8_componentes_mm":{"type":"number"},"delta_abs_mm":{"type":"number"},"delta_pct":{"type":"number"},"cierre_al_peso":{"type":"boolean"},"componentes":{"type":"array","items":{"type":"object","properties":{"tipo_codigo":{"type":"string"},"tipo_nombre_corto":{"type":"string"},"monto_mxn_mm":{"type":"number"},"pct_del_sar":{"type":"number"}},"required":["tipo_codigo","tipo_nombre_corto","monto_mxn_mm","pct_del_sar"]}},"caveats":{"type":"array","items":{"type":"string"}},"identidad_caveat":{"type":"string"}},"required":["fecha","unit","sar_total_reportado_mm","suma_8_componentes_mm","delta_abs_mm","delta_pct","cierre_al_peso","componentes","caveats","identidad_caveat"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/recursos/serie":{"get":{"tags":["consar"],"operationId":"get_serie_api_v1_consar_recursos_serie_get","summary":"Serie temporal por tipo de recurso (opcionalmente filtrada por AFORE)","description":"Retorna la serie mensual agregada del tipo de recurso indicado. Si `afore_codigo` se omite, suma todas las AFOREs (nacional). Parámetros `desde`/`hasta` aceptan YYYY-MM o YYYY-MM-01; default a la cobertura completa 1998-05 / 2025-06.","parameters":[{"schema":{"type":"string","description":"Código del tipo_recurso (p. ej. 'vivienda', 'rcv_imss', 'sar_total')"},"required":true,"description":"Código del tipo_recurso (p. ej. 'vivienda', 'rcv_imss', 'sar_total')","name":"codigo","in":"query"},{"schema":{"type":"string","description":"Código AFORE opcional (p. ej. 'pension_bienestar'); si se omite, suma nacional"},"required":false,"description":"Código AFORE opcional (p. ej. 'pension_bienestar'); si se omite, suma nacional","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 1998-05)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 1998-05)","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 2025-06)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 2025-06)","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"tipo_recurso":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"nombre_oficial":{"type":"string"},"categoria":{"type":"string"}},"required":["codigo","nombre_corto","nombre_oficial","categoria"]},"afore":{"type":["object","null"],"properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"monto_mxn_mm":{"type":"number"}},"required":["fecha","monto_mxn_mm"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["tipo_recurso","afore","unit","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/comisiones/serie":{"get":{"tags":["consar"],"operationId":"get_comisiones_serie_api_v1_consar_comisiones_serie_get","summary":"Serie temporal: comisión cobrada por AFORE (% anual sobre saldo)","description":"Retorna la serie mensual de comisiones cobradas por una AFORE específica (o todas si se omite `afore_codigo`). Comisión expresada como porcentaje anual sobre saldo administrado (e.g. 1.96 = 1.96%). Cobertura 2008-03-01 → 2025-06-01.","parameters":[{"schema":{"type":"string","description":"Código AFORE opcional (e.g. 'profuturo')"},"required":false,"description":"Código AFORE opcional (e.g. 'profuturo')","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 2008-03)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 2008-03)","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 2025-06)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 2025-06)","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":["object","null"],"properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"comision_pct":{"type":"number"}},"required":["fecha","comision_pct"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","unit","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/comisiones/snapshot":{"get":{"tags":["consar"],"operationId":"get_comisiones_snapshot_api_v1_consar_comisiones_snapshot_get","summary":"Snapshot mensual: comisión cobrada por cada AFORE en una fecha específica","description":"Retorna para la fecha indicada (YYYY-MM o YYYY-MM-01) la comisión cobrada por cada una de las 10 AFOREs reportantes. Incluye promedio simple, mínima y máxima del sistema. Pensión Bienestar excluida (régimen sin comisión sobre saldo).","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (cobertura 2008-03 a 2025-06)"},"required":true,"description":"YYYY-MM o YYYY-MM-01 (cobertura 2008-03 a 2025-06)","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"n_afores_reportando":{"type":"integer"},"promedio_simple_pct":{"type":"number"},"minima_pct":{"type":"number"},"maxima_pct":{"type":"number"},"afores":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"},"comision_pct":{"type":["number","null"]}},"required":["afore_codigo","afore_nombre_corto","tipo_pension","comision_pct"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","unit","n_afores_reportando","promedio_simple_pct","minima_pct","maxima_pct","afores","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/flujos/serie":{"get":{"tags":["consar"],"operationId":"get_flujos_serie_api_v1_consar_flujos_serie_get","summary":"Serie temporal: entradas/salidas mensuales por AFORE (o sistema)","description":"Retorna serie mensual de aportaciones brutas (`montos_entradas`) y retiros (`montos_salidas`) en mm MXN corrientes. Si `afore_codigo` se omite, suma sobre todas las AFOREs reportantes (sistema). Cobertura 2009-01-01 → 2025-06-01. `flujo_neto = montos_entradas - montos_salidas` (positivo = AFORE captando neto).","parameters":[{"schema":{"type":"string","description":"Código AFORE opcional (e.g. 'xxi_banorte')"},"required":false,"description":"Código AFORE opcional (e.g. 'xxi_banorte')","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 2009-01)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 2009-01)","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01 (default 2025-06)"},"required":false,"description":"YYYY-MM o YYYY-MM-01 (default 2025-06)","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":["object","null"],"properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"montos_entradas":{"type":"number"},"montos_salidas":{"type":"number"},"flujo_neto":{"type":"number"}},"required":["fecha","montos_entradas","montos_salidas","flujo_neto"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","unit","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/flujos/snapshot":{"get":{"tags":["consar"],"operationId":"get_flujos_snapshot_api_v1_consar_flujos_snapshot_get","summary":"Snapshot mensual: entradas/salidas por AFORE en una fecha","description":"Retorna para la fecha indicada (YYYY-MM o YYYY-MM-01) los flujos por cada AFORE reportante + totales del sistema. Cobertura 2009-01 → 2025-06.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"n_afores_reportando":{"type":"integer"},"sistema_entradas_mm":{"type":"number"},"sistema_salidas_mm":{"type":"number"},"sistema_flujo_neto_mm":{"type":"number"},"afores":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"},"montos_entradas":{"type":"number"},"montos_salidas":{"type":"number"},"flujo_neto":{"type":"number"}},"required":["afore_codigo","afore_nombre_corto","tipo_pension","montos_entradas","montos_salidas","flujo_neto"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","unit","n_afores_reportando","sistema_entradas_mm","sistema_salidas_mm","sistema_flujo_neto_mm","afores","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/traspasos/serie":{"get":{"tags":["consar"],"operationId":"get_traspasos_serie_api_v1_consar_traspasos_serie_get","summary":"Serie temporal: cuentas cedidas/recibidas en traspasos por AFORE (o sistema)","description":"Retorna serie mensual de cuentas cedidas (perdidas) y recibidas (ganadas) en traspasos AFORE-AFORE. Si `afore_codigo` se omite, suma sobre todas las AFOREs. Cobertura 1998-11-01 → 2025-06-01. `traspaso_neto = recibido - cedido` (positivo = AFORE ganando cuentas neto).","parameters":[{"schema":{"type":"string"},"required":false,"name":"afore_codigo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"desde","in":"query"},{"schema":{"type":"string"},"required":false,"name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":["object","null"],"properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"num_tras_cedido":{"type":["integer","null"]},"num_tras_recibido":{"type":["integer","null"]},"traspaso_neto":{"type":["integer","null"]}},"required":["fecha","num_tras_cedido","num_tras_recibido","traspaso_neto"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/traspasos/snapshot":{"get":{"tags":["consar"],"operationId":"get_traspasos_snapshot_api_v1_consar_traspasos_snapshot_get","summary":"Snapshot mensual: traspasos por AFORE + identidad Σced=Σrec","description":"Retorna para la fecha indicada los traspasos cedidos/recibidos por cada AFORE reportante. Incluye verificación de la identidad implícita Σ cedidos = Σ recibidos (cada traspaso es 1+1).","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"n_afores_reportando":{"type":"integer"},"identidad":{"type":"object","properties":{"sistema_total_cedido":{"type":"integer"},"sistema_total_recibido":{"type":"integer"},"delta":{"type":"integer"},"cierre_al_unidad":{"type":"boolean"}},"required":["sistema_total_cedido","sistema_total_recibido","delta","cierre_al_unidad"]},"afores":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"},"num_tras_cedido":{"type":["integer","null"]},"num_tras_recibido":{"type":["integer","null"]},"traspaso_neto":{"type":["integer","null"]}},"required":["afore_codigo","afore_nombre_corto","tipo_pension","num_tras_cedido","num_tras_recibido","traspaso_neto"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","n_afores_reportando","identidad","afores","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/pea-cotizantes/serie":{"get":{"tags":["consar"],"operationId":"get_pea_cotizantes_api_v1_consar_pea_cotizantes_serie_get","summary":"Serie anual: cobertura SAR sobre PEA mexicana (2010-2024)","description":"Retorna la serie anual nacional de la cobertura del SAR (cotizantes formales) sobre la PEA (Población Económicamente Activa) total. Incluye `brecha_no_cubierta_pct` (=100 - porcentaje) que integra informalidad, desempleo y elegibles no registrados. Cobertura 2010 → 2024 (15 puntos).","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"n_puntos":{"type":"integer"},"anio_min":{"type":"integer"},"anio_max":{"type":"integer"},"serie":{"type":"array","items":{"type":"object","properties":{"anio":{"type":"integer"},"cotizantes":{"type":"integer"},"pea":{"type":"integer"},"porcentaje_pea_afore":{"type":"number"},"brecha_no_cubierta_pct":{"type":"number"}},"required":["anio","cotizantes","pea","porcentaje_pea_afore","brecha_no_cubierta_pct"]}},"cobertura_min_pct":{"type":"number"},"cobertura_min_anio":{"type":"integer"},"cobertura_max_pct":{"type":"number"},"cobertura_max_anio":{"type":"integer"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["n_puntos","anio_min","anio_max","serie","cobertura_min_pct","cobertura_min_anio","cobertura_max_pct","cobertura_max_anio","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/activo-neto/serie":{"get":{"tags":["consar"],"operationId":"get_activo_neto_serie_api_v1_consar_activo_neto_serie_get","summary":"Serie temporal: activo neto atómico por (AFORE × SIEFORE)","description":"Retorna serie mensual de activo neto en MXN millones para una tupla (afore, siefore). Si la tupla proviene de un sub-variant concat decompuesto, expone mapping_validated y validated_via para transparencia. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)"},"required":true,"description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_siefore (e.g. sb 55-59, sps1)"},"required":true,"description":"slug en consar.cat_siefore (e.g. sb 55-59, sps1)","name":"siefore_slug","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"monto_mxn_mm":{"type":["number","null"]}},"required":["fecha","monto_mxn_mm"]}},"mapping_meta":{"type":"object","properties":{"is_subvariant_decomposed":{"type":"boolean"},"mapping_validated":{"type":["boolean","null"]},"validated_via":{"type":["string","null"]}},"required":["is_subvariant_decomposed","mapping_validated","validated_via"]},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","siefore","unit","n_puntos","rango","serie","mapping_meta","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/activo-neto/snapshot":{"get":{"tags":["consar"],"operationId":"get_activo_neto_snapshot_api_v1_consar_activo_neto_snapshot_get","summary":"Snapshot mensual: matriz (AFORE × SIEFORE) de activo neto","description":"Retorna para una fecha mensual todas las tuplas (afore, siefore) con sus montos. Útil para dashboards de composición por afore. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"unit":{"type":"string"},"n_filas":{"type":"integer"},"monto_total_mm":{"type":"number"},"n_filas_null":{"type":"integer"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"siefore_slug":{"type":"string"},"siefore_nombre":{"type":"string"},"siefore_categoria":{"type":"string"},"monto_mxn_mm":{"type":["number","null"]}},"required":["afore_codigo","afore_nombre_corto","siefore_slug","siefore_nombre","siefore_categoria","monto_mxn_mm"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","unit","n_filas","monto_total_mm","n_filas_null","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/activo-neto/agregado":{"get":{"tags":["consar"],"operationId":"get_activo_neto_agregado_api_v1_consar_activo_neto_agregado_get","summary":"Serie temporal: agregado de activo neto por categoría (totales por afore)","description":"Retorna serie mensual de un agregado total reportado en CSV por afore. Categorías: act_neto_total_siefores, act_neto_total_basicas, act_neto_total_adicionales (esta última con 0 rows post-S16 — schema preparado, ver caveats). Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores"},"required":true,"description":"codigo en consar.afores","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"act_neto_total_siefores | act_neto_total_basicas | act_neto_total_adicionales"},"required":true,"description":"act_neto_total_siefores | act_neto_total_basicas | act_neto_total_adicionales","name":"categoria","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"categoria":{"type":"string"},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"monto_mxn_mm":{"type":["number","null"]}},"required":["fecha","monto_mxn_mm"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","categoria","unit","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/rendimientos/serie":{"get":{"tags":["consar"],"operationId":"get_rendimiento_serie_api_v1_consar_rendimientos_serie_get","summary":"Serie temporal: rendimiento atómico por (AFORE × SIEFORE × PLAZO)","description":"Retorna serie mensual de rendimiento (% anualizado neto) para una tupla (afore, siefore, plazo). Si la tupla proviene de un sub-variant concat decompuesto, expone mapping_validated y validated_via. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)"},"required":true,"description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3)"},"required":true,"description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3)","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"12_meses | 24_meses | 36_meses | 5_anios | historico"},"required":true,"description":"12_meses | 24_meses | 36_meses | 5_anios | historico","name":"plazo","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"plazo":{"type":"string"},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"rendimiento_pct":{"type":"number"}},"required":["fecha","rendimiento_pct"]}},"mapping_meta":{"type":"object","properties":{"is_subvariant_decomposed":{"type":"boolean"},"mapping_validated":{"type":["boolean","null"]},"validated_via":{"type":["string","null"]}},"required":["is_subvariant_decomposed","mapping_validated","validated_via"]},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","siefore","plazo","unit","n_puntos","rango","serie","mapping_meta","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/rendimientos/snapshot":{"get":{"tags":["consar"],"operationId":"get_rendimiento_snapshot_api_v1_consar_rendimientos_snapshot_get","summary":"Snapshot mensual: matriz (AFORE × SIEFORE) de rendimiento para un plazo","description":"Retorna para una fecha y plazo todas las tuplas (afore, siefore) con sus rendimientos. Útil para dashboards comparativos de desempeño. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"},{"schema":{"type":"string","description":"12_meses | 24_meses | 36_meses | 5_anios | historico"},"required":true,"description":"12_meses | 24_meses | 36_meses | 5_anios | historico","name":"plazo","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"plazo":{"type":"string"},"unit":{"type":"string"},"n_filas":{"type":"integer"},"rendimiento_min":{"type":"number"},"rendimiento_max":{"type":"number"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"siefore_slug":{"type":"string"},"siefore_nombre":{"type":"string"},"siefore_categoria":{"type":"string"},"rendimiento_pct":{"type":"number"}},"required":["afore_codigo","afore_nombre_corto","siefore_slug","siefore_nombre","siefore_categoria","rendimiento_pct"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","plazo","unit","n_filas","rendimiento_min","rendimiento_max","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/rendimientos/sistema":{"get":{"tags":["consar"],"operationId":"get_rendimiento_sistema_api_v1_consar_rendimientos_sistema_get","summary":"Serie temporal: rendimiento agregado del sistema (INTER-afore) por SIEFORE × PLAZO","description":"Retorna serie mensual del rendimiento agregado CONSAR del sistema (promedio ponderado sobre todas las afores) para una siefore y plazo. Distinto de activo_neto_agg que es agregado INTRA-afore. Para 'adicionales' usar siefore_slug='agregado_adicionales'. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"slug en consar.cat_siefore (e.g. sb 60-64, agregado_adicionales)"},"required":true,"description":"slug en consar.cat_siefore (e.g. sb 60-64, agregado_adicionales)","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"12_meses | 24_meses | 36_meses | 5_anios | historico"},"required":true,"description":"12_meses | 24_meses | 36_meses | 5_anios | historico","name":"plazo","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"plazo":{"type":"string"},"unit":{"type":"string"},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"rendimiento_pct":{"type":"number"}},"required":["fecha","rendimiento_pct"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["siefore","plazo","unit","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/metricas-sensibilidad":{"get":{"tags":["consar"],"operationId":"get_metricas_sensibilidad_api_v1_consar_metricas_sensibilidad_get","summary":"Catálogo descubrible: 7 métricas de sensibilidad regulatoria","description":"Retorna las 7 métricas de sensibilidad regulatoria reportadas en dataset #03 (coef_liquidez, dcvar, tracking_error, escenarios_var, ppp, pid, var) con su unidad y descripción. Útil para clientes que necesitan descubrir slugs válidos antes de consultar /medidas/serie o /medidas/snapshot.","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"metricas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"columna_csv":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"},"orden_display":{"type":"integer"}},"required":["id","slug","columna_csv","descripcion","unidad","orden_display"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["n","metricas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/medidas/serie":{"get":{"tags":["consar"],"operationId":"get_medida_serie_api_v1_consar_medidas_serie_get","summary":"Serie temporal: medida regulatoria por (AFORE × SIEFORE × MÉTRICA)","description":"Retorna serie mensual de una métrica de sensibilidad regulatoria para una tupla (afore, siefore, métrica). Si la tupla proviene de un sub-variant decompuesto, expone mapping_validated y validated_via. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)"},"required":true,"description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3)"},"required":true,"description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3)","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_metrica_sensibilidad (e.g. var, ppp, pid)"},"required":true,"description":"slug en consar.cat_metrica_sensibilidad (e.g. var, ppp, pid)","name":"metrica","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"metrica":{"type":"object","properties":{"slug":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"}},"required":["slug","descripcion","unidad"]},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"valor":{"type":"number"}},"required":["fecha","valor"]}},"mapping_meta":{"type":"object","properties":{"is_subvariant_decomposed":{"type":"boolean"},"mapping_validated":{"type":["boolean","null"]},"validated_via":{"type":["string","null"]}},"required":["is_subvariant_decomposed","mapping_validated","validated_via"]},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","siefore","metrica","n_puntos","rango","serie","mapping_meta","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/medidas/snapshot":{"get":{"tags":["consar"],"operationId":"get_medida_snapshot_api_v1_consar_medidas_snapshot_get","summary":"Snapshot mensual: matriz (AFORE × SIEFORE) de una métrica para una fecha","description":"Retorna para una fecha y métrica todas las tuplas (afore, siefore) con su valor. Útil para dashboards comparativos de exposición regulatoria. Cobertura 2019-12 → 2025-06.","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_metrica_sensibilidad"},"required":true,"description":"slug en consar.cat_metrica_sensibilidad","name":"metrica","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"metrica":{"type":"object","properties":{"slug":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"}},"required":["slug","descripcion","unidad"]},"n_filas":{"type":"integer"},"valor_min":{"type":"number"},"valor_max":{"type":"number"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"siefore_slug":{"type":"string"},"siefore_nombre":{"type":"string"},"siefore_categoria":{"type":"string"},"valor":{"type":"number"}},"required":["afore_codigo","afore_nombre_corto","siefore_slug","siefore_nombre","siefore_categoria","valor"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","metrica","n_filas","valor_min","valor_max","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/metricas-cuenta":{"get":{"tags":["consar"],"operationId":"get_metricas_cuenta_api_v1_consar_metricas_cuenta_get","summary":"Catálogo descubrible: 11 métricas operacionales de cuentas administradas","description":"Retorna las 11 métricas operacionales reportadas en dataset #05 (cuentas_inhabilitadas, total_cuentas_afores, trabajadores_imss/issste/registrados/asignados/independientes, etc.) con su unidad (count BIGINT) y desde_fecha (primera fecha empírica). Útil para clientes que descubren slugs antes de consultar /cuentas/serie, /cuentas/snapshot o /cuentas/sistema.","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"metricas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"columna_csv":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"},"desde_fecha":{"type":"string"},"orden_display":{"type":"integer"},"notas":{"type":["string","null"]}},"required":["id","slug","columna_csv","descripcion","unidad","desde_fecha","orden_display","notas"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["n","metricas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/cuentas/serie":{"get":{"tags":["consar"],"operationId":"get_cuenta_serie_api_v1_consar_cuentas_serie_get","summary":"Serie temporal: métrica de cuenta por (AFORE × MÉTRICA)","description":"Retorna serie mensual de una métrica operacional para una afore commercial. Cobertura por métrica (desde_fecha): 1997-12+ (core), 2001-06+ (asignados), 2012-01+ (subdivisiones bm/siefores), 2005-08+ (independientes/issste), 2024-09+ (cuentas_inhabilitadas reforma 2024). Para etiquetas no-commercial (total_sar, bienestar_010, prestadora_de_servicios) usar /cuentas/sistema.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)"},"required":true,"description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_metrica_cuenta (e.g. trabajadores_imss, total_cuentas_afores)"},"required":true,"description":"slug en consar.cat_metrica_cuenta (e.g. trabajadores_imss, total_cuentas_afores)","name":"metrica","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"metrica":{"type":"object","properties":{"slug":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"},"desde_fecha":{"type":"string"}},"required":["slug","descripcion","unidad","desde_fecha"]},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"valor":{"type":"integer"}},"required":["fecha","valor"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","metrica","n_puntos","rango","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/cuentas/snapshot":{"get":{"tags":["consar"],"operationId":"get_cuenta_snapshot_api_v1_consar_cuentas_snapshot_get","summary":"Snapshot mensual: matriz (AFORE × MÉTRICA) en una fecha","description":"Retorna para una fecha todas las tuplas (afore commercial, métrica) con su valor. Útil para dashboards comparativos de operación administrativa. Cobertura 1997-12 → 2025-06 (algunas afores no operaron desde 1997).","parameters":[{"schema":{"type":"string","description":"YYYY-MM o YYYY-MM-01"},"required":true,"description":"YYYY-MM o YYYY-MM-01","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"n_filas":{"type":"integer"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"metrica_slug":{"type":"string"},"metrica_descripcion":{"type":"string"},"valor":{"type":"integer"}},"required":["afore_codigo","afore_nombre_corto","metrica_slug","metrica_descripcion","valor"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","n_filas","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/cuentas/sistema":{"get":{"tags":["consar"],"operationId":"get_cuenta_sistema_api_v1_consar_cuentas_sistema_get","summary":"Serie sistema: 3 etiquetas no-commercial (total SAR + bienestar + prestadora)","description":"Retorna serie temporal de las 3 etiquetas no-commercial agrupadas: total_cuentas_sar (sistema_total), cuentas_bienestar_010 (sistema_categoria_especial), prestadora_de_servicios (administrativa_especial). Permite componer la identidad SAR triple-capa en frontend. Cada etiqueta reporta UNA métrica específica: total_cuentas_sar reporta total_cuentas_sar; cuentas_bienestar_010 reporta cuentas_bienestar_010; prestadora_de_servicios reporta cuentas_inhabilitadas.","parameters":[{"schema":{"type":"string","description":"slug en consar.cat_metrica_cuenta (e.g. total_cuentas_sar, cuentas_bienestar_010, cuentas_inhabilitadas)"},"required":true,"description":"slug en consar.cat_metrica_cuenta (e.g. total_cuentas_sar, cuentas_bienestar_010, cuentas_inhabilitadas)","name":"metrica","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"n_puntos":{"type":"integer"},"etiquetas":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"nombre_display":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre_display","categoria"]}},"metricas":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"},"desde_fecha":{"type":"string"}},"required":["slug","descripcion","unidad","desde_fecha"]}},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"etiqueta_slug":{"type":"string"},"etiqueta_categoria":{"type":"string"},"metrica_slug":{"type":"string"},"valor":{"type":"integer"}},"required":["fecha","etiqueta_slug","etiqueta_categoria","metrica_slug","valor"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["n_puntos","etiquetas","metricas","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios/serie":{"get":{"tags":["consar"],"operationId":"get_precio_serie_api_v1_consar_precios_serie_get","summary":"Serie diaria NAV: precio por (AFORE × SIEFORE)","description":"Retorna serie diaria de precios NAV (Net Asset Value) en MXN para una tupla (afore, siefore). Cobertura más profunda del proyecto: 1997-01-08 → 2025-12-06 (28 años). Ventana opcional desde/hasta para reducir payload.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)"},"required":true,"description":"codigo en consar.afores (e.g. xxi_banorte, profuturo)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3, siav)"},"required":true,"description":"slug en consar.cat_siefore (e.g. sb 60-64, sps3, siav)","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD opcional"},"required":false,"description":"YYYY-MM-DD opcional","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD opcional"},"required":false,"description":"YYYY-MM-DD opcional","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"precio_min":{"type":"number"},"precio_max":{"type":"number"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"precio":{"type":"number"}},"required":["fecha","precio"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","siefore","n_puntos","rango","precio_min","precio_max","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios/snapshot":{"get":{"tags":["consar"],"operationId":"get_precio_snapshot_api_v1_consar_precios_snapshot_get","summary":"Snapshot diario: matriz (AFORE × SIEFORE) en una fecha","description":"Retorna para una fecha de mercado todos los pares (afore commercial × siefore) con su precio NAV. Útil para dashboards comparativos diarios. Si fecha no es hábil → 404 (verificar disponibilidad).","parameters":[{"schema":{"type":"string","description":"YYYY-MM-DD (fecha hábil de mercado)"},"required":true,"description":"YYYY-MM-DD (fecha hábil de mercado)","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"n_filas":{"type":"integer"},"precio_min":{"type":"number"},"precio_max":{"type":"number"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"siefore_slug":{"type":"string"},"siefore_nombre":{"type":"string"},"siefore_categoria":{"type":"string"},"precio":{"type":"number"}},"required":["afore_codigo","afore_nombre_corto","siefore_slug","siefore_nombre","siefore_categoria","precio"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","n_filas","precio_min","precio_max","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios/comparativo":{"get":{"tags":["consar"],"operationId":"get_precio_comparativo_api_v1_consar_precios_comparativo_get","summary":"Comparativo: misma SIEFORE entre N afores en ventana temporal","description":"Retorna serie diaria de precio NAV de la misma siefore para todas las afores que la reportan, dentro de una ventana temporal OBLIGATORIA. Caso de uso: comparar performance NAV entre afores. La ventana es obligatoria para protección del server (payload sin ventana podría ser 7K×11=77K puntos).","parameters":[{"schema":{"type":"string","description":"slug en consar.cat_siefore"},"required":true,"description":"slug en consar.cat_siefore","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD (obligatorio)"},"required":true,"description":"YYYY-MM-DD (obligatorio)","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD (obligatorio)"},"required":true,"description":"YYYY-MM-DD (obligatorio)","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"n_afores":{"type":"integer"},"series":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"n_puntos":{"type":"integer"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"precio":{"type":"number"}},"required":["fecha","precio"]}}},"required":["afore_codigo","afore_nombre_corto","n_puntos","serie"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["siefore","rango","n_afores","series","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios-gestion/serie":{"get":{"tags":["consar"],"operationId":"get_precio_gestion_serie_api_v1_consar_precios_gestion_serie_get","summary":"Serie diaria gestión: precio interno por (AFORE × SIEFORE)","description":"Retorna serie diaria de precios de gestión interna en MXN para una tupla (afore, siefore). Cobertura 1997-01-07 → 2025-12-06 (28+ años, 7,060 fechas). Range NAV +30% vs precio_bolsa: distinta base/comisión. NO incluye PensionISSSTE.","parameters":[{"schema":{"type":"string","description":"codigo en consar.afores (NO incluye pensionissste en #11)"},"required":true,"description":"codigo en consar.afores (NO incluye pensionissste en #11)","name":"afore_codigo","in":"query"},{"schema":{"type":"string","description":"slug en consar.cat_siefore (incluye sb5 legacy XXI)"},"required":true,"description":"slug en consar.cat_siefore (incluye sb5 legacy XXI)","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD opcional"},"required":false,"description":"YYYY-MM-DD opcional","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD opcional"},"required":false,"description":"YYYY-MM-DD opcional","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"afore":{"type":"object","properties":{"codigo":{"type":"string"},"nombre_corto":{"type":"string"},"tipo_pension":{"type":"string"}},"required":["codigo","nombre_corto","tipo_pension"]},"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"n_puntos":{"type":"integer"},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"precio_min":{"type":"number"},"precio_max":{"type":"number"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"precio":{"type":"number"}},"required":["fecha","precio"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["afore","siefore","n_puntos","rango","precio_min","precio_max","serie","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios-gestion/snapshot":{"get":{"tags":["consar"],"operationId":"get_precio_gestion_snapshot_api_v1_consar_precios_gestion_snapshot_get","summary":"Snapshot gestión: matriz (AFORE × SIEFORE) en una fecha","description":"Retorna para una fecha de mercado todos los pares (afore × siefore) con su precio de gestión interna. Útil para dashboards comparativos diarios. Si fecha no es hábil → 404. NO incluye PensionISSSTE.","parameters":[{"schema":{"type":"string","description":"YYYY-MM-DD (fecha hábil de mercado)"},"required":true,"description":"YYYY-MM-DD (fecha hábil de mercado)","name":"fecha","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"fecha":{"type":"string"},"n_filas":{"type":"integer"},"precio_min":{"type":"number"},"precio_max":{"type":"number"},"filas":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"siefore_slug":{"type":"string"},"siefore_nombre":{"type":"string"},"siefore_categoria":{"type":"string"},"precio":{"type":"number"}},"required":["afore_codigo","afore_nombre_corto","siefore_slug","siefore_nombre","siefore_categoria","precio"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["fecha","n_filas","precio_min","precio_max","filas","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/consar/precios-gestion/comparativo":{"get":{"tags":["consar"],"operationId":"get_precio_gestion_comparativo_api_v1_consar_precios_gestion_comparativo_get","summary":"Comparativo gestión: misma SIEFORE entre N afores en ventana","description":"Retorna serie diaria de precio gestión interna de la misma siefore para todas las afores que la reportan, dentro de una ventana temporal OBLIGATORIA. Caso de uso: comparar performance gestión interna entre afores. La ventana es obligatoria para protección del server (payload sin ventana podría ser 7K×10=70K puntos).","parameters":[{"schema":{"type":"string","description":"slug en consar.cat_siefore"},"required":true,"description":"slug en consar.cat_siefore","name":"siefore_slug","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD (obligatorio)"},"required":true,"description":"YYYY-MM-DD (obligatorio)","name":"desde","in":"query"},{"schema":{"type":"string","description":"YYYY-MM-DD (obligatorio)"},"required":true,"description":"YYYY-MM-DD (obligatorio)","name":"hasta","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","properties":{"siefore":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"categoria":{"type":"string"}},"required":["slug","nombre","categoria"]},"rango":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["desde","hasta"]},"n_afores":{"type":"integer"},"series":{"type":"array","items":{"type":"object","properties":{"afore_codigo":{"type":"string"},"afore_nombre_corto":{"type":"string"},"n_puntos":{"type":"integer"},"serie":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"precio":{"type":"number"}},"required":["fecha","precio"]}}},"required":["afore_codigo","afore_nombre_corto","n_puntos","serie"]}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["siefore","rango","n_afores","series","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/metadata":{"get":{"tags":["enigh"],"operationId":"enigh_metadata_api_v1_enigh_metadata_get","summary":"Enigh Metadata","description":"Metadata del dataset ENIGH 2024 NS: edición, fuentes, schema, totales.","responses":{"200":{"description":"Metadata completa del dataset ENIGH 2024 NS.","content":{"application/json":{"schema":{"type":"object","properties":{"edition":{"type":"string"},"periodicity":{"type":"string"},"reference_date":{"type":"string"},"schema_version":{"type":"string"},"last_updated":{"type":"string"},"total_hogares_muestra":{"type":"integer"},"total_hogares_expandido":{"type":"integer"},"total_tablas_ingestadas":{"type":"integer"},"total_catalogos":{"type":"integer"},"sources":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"consulted_on":{"type":"string"}},"required":["title","url","consulted_on"]}},"methodology_notes":{"type":"array","items":{"type":"string"}}},"required":["edition","periodicity","reference_date","schema_version","last_updated","total_hogares_muestra","total_hogares_expandido","total_tablas_ingestadas","total_catalogos","sources","methodology_notes"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/validaciones":{"get":{"tags":["enigh"],"operationId":"enigh_validaciones_api_v1_enigh_validaciones_get","summary":"Enigh Validaciones","description":"Los 13 bounds HIGH vs INEGI oficial (Comunicado 112/25).\n\n- 3 bounds ingreso (total, decil 1, decil 10) — trimestrales\n- 10 bounds gasto (gasto_mon + 9 rubros) — mensuales\n\nTodos reproducen al peso al 2026-04-22 (ver proyect memory S3, S5).","responses":{"200":{"description":"13 bounds HIGH vs INEGI Comunicado 112/25 (3 ingreso trimestrales + 10 gasto mensuales).","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"passing":{"type":"integer"},"failing":{"type":"integer"},"bounds":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"scope":{"type":"string"},"metric":{"type":"string"},"column":{"type":"string"},"unit":{"type":"string"},"calculado":{"type":"number"},"oficial":{"type":"number"},"delta_pct":{"type":"number"},"tolerance_pct":{"type":"number"},"passing":{"type":"boolean"},"source":{"type":"string"}},"required":["id","scope","metric","column","unit","calculado","oficial","delta_pct","tolerance_pct","passing","source"]}}},"required":["count","passing","failing","bounds"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/hogares/summary":{"get":{"tags":["enigh"],"operationId":"hogares_summary_api_v1_enigh_hogares_summary_get","summary":"Hogares Summary","description":"Agregado nacional ponderado: hogares muestra + expandido, mean ing_cor, mean gasto_mon.","responses":{"200":{"description":"Agregado nacional ponderado de hogares ENIGH 2024 NS.","content":{"application/json":{"schema":{"type":"object","properties":{"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"mean_ing_cor_trim":{"type":"number"},"mean_ing_cor_mensual":{"type":"number"},"mean_gasto_mon_trim":{"type":"number"},"mean_gasto_mon_mensual":{"type":"number"},"edition":{"type":"string"},"source":{"type":"string"}},"required":["n_hogares_muestra","n_hogares_expandido","mean_ing_cor_trim","mean_ing_cor_mensual","mean_gasto_mon_trim","mean_gasto_mon_mensual","edition","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/hogares/by-decil":{"get":{"tags":["enigh"],"operationId":"hogares_by_decil_api_v1_enigh_hogares_by_decil_get","summary":"Hogares By Decil","description":"Distribución de ingreso/gasto por decil nacional (factor-weighted cumulative, INEGI-standard).","responses":{"200":{"description":"10 deciles nacionales por factor-weighted cumulative sum (INEGI-standard).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"decil":{"type":"integer"},"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"mean_ing_cor_trim":{"type":"number"},"mean_ing_cor_mensual":{"type":"number"},"mean_gasto_mon_trim":{"type":"number"},"share_factor_pct":{"type":"number"}},"required":["decil","n_hogares_muestra","n_hogares_expandido","mean_ing_cor_trim","mean_ing_cor_mensual","mean_gasto_mon_trim","share_factor_pct"]}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/hogares/by-entidad":{"get":{"tags":["enigh"],"operationId":"hogares_by_entidad_api_v1_enigh_hogares_by_entidad_get","summary":"Hogares By Entidad","description":"Hogares agregados por entidad. Orden descendente por mean ing_cor.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$","description":"Clave entidad 2 dígitos (01-32). Si omite, devuelve las 32."},"required":false,"description":"Clave entidad 2 dígitos (01-32). Si omite, devuelve las 32.","name":"entidad","in":"query"}],"responses":{"200":{"description":"Hogares agregados por entidad federativa (32 filas o filtrado por `entidad`).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"mean_ing_cor_trim":{"type":"number"},"mean_ing_cor_mensual":{"type":"number"},"mean_gasto_mon_trim":{"type":"number"}},"required":["clave","nombre","n_hogares_muestra","n_hogares_expandido","mean_ing_cor_trim","mean_ing_cor_mensual","mean_gasto_mon_trim"]}}}}},"404":{"description":"`entidad` no encontrada en el filtro."},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/poblacion/demographics":{"get":{"tags":["enigh"],"operationId":"poblacion_demographics_api_v1_enigh_poblacion_demographics_get","summary":"Poblacion Demographics","description":"Pirámide demográfica ponderada: sexo + 5 cohortes etarios. Opcional por entidad.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"entidad","in":"query"}],"responses":{"200":{"description":"Pirámide demográfica ponderada (sexo + 5 cohortes etarios).","content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string"},"n_personas_muestra":{"type":"integer"},"n_personas_expandido":{"type":"integer"},"sexo":{"type":"array","items":{"type":"object","properties":{"sexo":{"type":"string"},"n_expandido":{"type":"integer"},"pct":{"type":"number"}},"required":["sexo","n_expandido","pct"]}},"edad":{"type":"array","items":{"type":"object","properties":{"bucket":{"type":"string"},"n_expandido":{"type":"integer"},"pct":{"type":"number"}},"required":["bucket","n_expandido","pct"]}}},"required":["scope","n_personas_muestra","n_personas_expandido","sexo","edad"]}}}},"404":{"description":"`entidad` no encontrada."},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/gastos/by-rubro":{"get":{"tags":["enigh"],"operationId":"gastos_by_rubro_api_v1_enigh_gastos_by_rubro_get","summary":"Gastos By Rubro","description":"Los 9 rubros INEGI desde concentradohogar (summary oficial).\n\nCuando `decil` se especifica, la query se filtra a ese decil y `pct_del_monetario`\nse calcula respecto al gasto_mon de ese decil. Los valores `oficial_mensual` solo\naplican al total nacional (no a deciles específicos).","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":10},"required":false,"name":"decil","in":"query"}],"responses":{"200":{"description":"9 rubros INEGI con cifra mensual y trimestral por hogar.","content":{"application/json":{"schema":{"type":"object","properties":{"decil":{"type":["integer","null"]},"mean_gasto_mon_trim":{"type":"number"},"rubros":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"mean_gasto_trim":{"type":"number"},"mean_gasto_mensual":{"type":"number"},"pct_del_monetario":{"type":"number"},"oficial_mensual":{"type":["number","null"]},"bound_delta_pct":{"type":["number","null"]}},"required":["slug","nombre","mean_gasto_trim","mean_gasto_mensual","pct_del_monetario","oficial_mensual","bound_delta_pct"]}}},"required":["decil","mean_gasto_mon_trim","rubros"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/actividad/agro":{"get":{"tags":["enigh"],"operationId":"actividad_agro_api_v1_enigh_actividad_agro_get","summary":"Actividad Agro","description":"Hogares con actividad agropecuaria. Cobertura, distribución por decil, top entidades, ventas.","responses":{"200":{"description":"Hogares con actividad agropecuaria por decil nacional (DISTINCT folioviv/foliohog).","content":{"application/json":{"schema":{"type":"object","properties":{"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"pct_del_universo":{"type":"number"},"sum_ventas_trim":{"type":"integer"},"sum_gasto_negocio_trim":{"type":"integer"},"mean_ventas_por_hogar":{"type":"number"},"por_decil":{"type":"array","items":{"type":"object","properties":{"decil":{"type":"integer"},"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"pct_share_actividad":{"type":"number"}},"required":["decil","n_hogares_muestra","n_hogares_expandido","pct_share_actividad"]}},"top_entidades":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"n_hogares_expandido":{"type":"integer"}},"required":["clave","nombre","n_hogares_expandido"]}},"note":{"type":"string"}},"required":["n_hogares_muestra","n_hogares_expandido","pct_del_universo","sum_ventas_trim","sum_gasto_negocio_trim","mean_ventas_por_hogar","por_decil","top_entidades","note"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/actividad/noagro":{"get":{"tags":["enigh"],"operationId":"actividad_noagro_api_v1_enigh_actividad_noagro_get","summary":"Actividad Noagro","description":"Hogares con actividad NO agropecuaria (comercio, servicios, manufactura).","responses":{"200":{"description":"Hogares con actividad no agropecuaria por decil nacional.","content":{"application/json":{"schema":{"type":"object","properties":{"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"pct_del_universo":{"type":"number"},"sum_ventas_trim":{"type":"integer"},"sum_ingreso_trim":{"type":"integer"},"mean_ventas_por_hogar":{"type":"number"},"por_decil":{"type":"array","items":{"type":"object","properties":{"decil":{"type":"integer"},"n_hogares_muestra":{"type":"integer"},"n_hogares_expandido":{"type":"integer"},"pct_share_actividad":{"type":"number"}},"required":["decil","n_hogares_muestra","n_hogares_expandido","pct_share_actividad"]}},"top_entidades":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"n_hogares_expandido":{"type":"integer"}},"required":["clave","nombre","n_hogares_expandido"]}},"note":{"type":"string"}},"required":["n_hogares_muestra","n_hogares_expandido","pct_del_universo","sum_ventas_trim","sum_ingreso_trim","mean_ventas_por_hogar","por_decil","top_entidades","note"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enigh/actividad/jcf":{"get":{"tags":["enigh"],"operationId":"actividad_jcf_api_v1_enigh_actividad_jcf_get","summary":"Actividad Jcf","description":"Beneficiarios del Programa Jóvenes Construyendo el Futuro (JCF).\n\nDataset pequeño (n=327 muestra). Distribución por entidad + promedio ingreso trimestral.\nExpandido usa poblacion.factor (factor de persona, no hogar) porque\nbeneficiarios son individuos.","responses":{"200":{"description":"Hogares con ingresos por Jóvenes Construyendo el Futuro (327 hogares muestra).","content":{"application/json":{"schema":{"type":"object","properties":{"n_beneficiarios_muestra":{"type":"integer"},"n_beneficiarios_expandido":{"type":"integer"},"sum_ingreso_trim":{"type":"integer"},"mean_ingreso_trim_por_beneficiario":{"type":"number"},"por_entidad":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"beneficiarios_muestra":{"type":"integer"},"beneficiarios_expandido":{"type":"integer"}},"required":["clave","nombre","beneficiarios_muestra","beneficiarios_expandido"]}},"note":{"type":"string"}},"required":["n_beneficiarios_muestra","n_beneficiarios_expandido","sum_ingreso_trim","mean_ingreso_trim_por_beneficiario","por_entidad","note"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/ingreso/cdmx-vs-nacional":{"get":{"tags":["comparativo"],"operationId":"ingreso_cdmx_vs_nacional_api_v1_comparativo_ingreso_cdmx_vs_nacional_get","summary":"Ingreso Cdmx Vs Nacional","description":"Compara ingreso mensual en las 3 referencias relevantes.\n\n- CDMX servidor (persona): mean/median de sueldo_bruto mensual\n- ENIGH hogar nacional: mean ing_cor trim/3 (ponderado factor)\n- ENIGH hogar CDMX (entidad 09): mean ing_cor trim/3 ponderado\n\nLas 3 cifras responden preguntas distintas. Brechas y ratios se calculan\nvs servidor mean (base común), pero son ilustrativos — las unidades no\nson directamente comparables (persona vs hogar).","responses":{"200":{"description":"Comparativo ingreso CDMX (padrón servidores) vs nacional (ENIGH).","content":{"application/json":{"schema":{"type":"object","properties":{"cdmx_servidor":{"type":"object","properties":{"unit":{"type":"string"},"n_servidores":{"type":"integer"},"mean_sueldo_bruto_mensual":{"type":"number"},"median_sueldo_bruto_mensual":{"type":"number"}},"required":["unit","n_servidores","mean_sueldo_bruto_mensual","median_sueldo_bruto_mensual"]},"enigh_hogar_nacional":{"type":"object","properties":{"unit":{"type":"string"},"scope":{"type":"string"},"n_hogares_expandido":{"type":"integer"},"mean_ing_cor_mensual":{"type":"number"}},"required":["unit","scope","n_hogares_expandido","mean_ing_cor_mensual"]},"enigh_hogar_cdmx":{"type":"object","properties":{"unit":{"type":"string"},"scope":{"type":"string"},"n_hogares_expandido":{"type":"integer"},"mean_ing_cor_mensual":{"type":"number"}},"required":["unit","scope","n_hogares_expandido","mean_ing_cor_mensual"]},"brecha_mean_servidor_vs_hogar_nacional":{"type":"number"},"ratio_hogar_nacional_sobre_servidor":{"type":"number"},"brecha_mean_servidor_vs_hogar_cdmx":{"type":"number"},"ratio_hogar_cdmx_sobre_servidor":{"type":"number"},"note":{"type":"string"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["cdmx_servidor","enigh_hogar_nacional","enigh_hogar_cdmx","brecha_mean_servidor_vs_hogar_nacional","ratio_hogar_nacional_sobre_servidor","brecha_mean_servidor_vs_hogar_cdmx","ratio_hogar_cdmx_sobre_servidor","note","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/decil-servidores-cdmx":{"get":{"tags":["comparativo"],"operationId":"decil_servidores_cdmx_api_v1_comparativo_decil_servidores_cdmx_get","summary":"Decil Servidores Cdmx","description":"Mapea percentiles del sueldo servidor CDMX a deciles ENIGH bajo 2 escenarios.\n\n**Escenario A — Perceptor único**: el servidor es la única fuente de\ningreso del hogar. Ingreso hogar ≈ sueldo_bruto servidor directo.\n\n**Escenario B — Servidor + perceptor mediano asalariado**: se asume el\nhogar con 2 perceptores: el servidor CDMX más una persona con ingreso\nequivalente a la mediana nacional de 'Sueldos, salarios o jornal'\n(enigh.ingresos.clave='P001'). Aproximación más defendible que\n'2× sueldo servidor' porque no asume que la pareja gana igual; ancla\nen una distribución empírica externa (n≈106k perceptores asalariados).\n\nLos deciles ENIGH se definen por bounds min/max de ing_cor trimestral\ndividido entre 3 para comparar mensual. Pueden haber huecos estrechos\nentre el upper de un decil y el lower del siguiente; el mapeo\ndevuelve el decil más cercano en esos casos.\n\nTESIS CENTRAL del observatorio: cuantifica el posicionamiento del\nservidor público CDMX dentro de la distribución de ingresos hogar a\nnivel nacional, con supuestos explícitos y acotación por escenarios.","responses":{"200":{"description":"Posición del padrón CDMX en los deciles nacionales ENIGH.","content":{"application/json":{"schema":{"type":"object","properties":{"cdmx_servidor":{"type":"object","additionalProperties":{}},"enigh_deciles_mensuales":{"type":"array","items":{"type":"object","properties":{"decil":{"type":"integer"},"lower_mensual":{"type":"number"},"upper_mensual":{"type":"number"}},"required":["decil","lower_mensual","upper_mensual"]}},"escenarios":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"supuesto":{"type":"string"},"ingreso_adicional_mensual":{"type":"number"},"mapeo":{"type":"array","items":{"type":"object","properties":{"percentil":{"type":"string"},"ingreso_hogar_supuesto_mensual":{"type":"number"},"decil_hogar_enigh":{"type":["integer","null"]}},"required":["percentil","ingreso_hogar_supuesto_mensual","decil_hogar_enigh"]}}},"required":["nombre","supuesto","ingreso_adicional_mensual","mapeo"]}},"narrative":{"type":"string"},"caveats":{"type":"array","items":{"type":"string"}},"caveats_interpretativos":{"type":"object","properties":{"frontera_p50":{"type":"string"},"narrativa_correcta":{"type":"string"},"insight_principal":{"type":"string"},"implicacion_narrativa":{"type":"string"}},"required":["frontera_p50","narrativa_correcta","insight_principal","implicacion_narrativa"]}},"required":["cdmx_servidor","enigh_deciles_mensuales","escenarios","narrative","caveats","caveats_interpretativos"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/aportes-vs-jubilaciones-actuales":{"get":{"tags":["comparativo"],"operationId":"aportes_vs_jubilaciones_actuales_api_v1_comparativo_aportes_vs_jubilaciones_actuales_get","summary":"Aportes Vs Jubilaciones Actuales","description":"Yuxtaposición descriptiva — NO proyección actuarial.\n\n- CDMX.deducciones (bruto - neto) es el agregado total: ISR + IMSS/ISSSTE\n  + SAR + otras deducciones. NO es separable a nivel registro.\n- ENIGH.jubilaciones son pensiones CURRENTLY cobradas por hogares ENIGH 2024\n  NS, no proyecciones de lo que recibirá un servidor CDMX al jubilarse.\n- Los sistemas y las generaciones tienen reglas distintas. La comparación\n  útil es magnitud relativa, no equivalencia.","responses":{"200":{"description":"Comparativo aportes SAR (descontados al servidor CDMX) vs jubilación actual ENIGH.","content":{"application/json":{"schema":{"type":"object","properties":{"cdmx_aportes_actuales":{"type":"object","properties":{"unit":{"type":"string"},"n_servidores":{"type":"integer"},"mean_sueldo_bruto":{"type":"number"},"mean_sueldo_neto":{"type":"number"},"mean_deduccion_total":{"type":"number"},"pct_deduccion_sobre_bruto":{"type":"number"}},"required":["unit","n_servidores","mean_sueldo_bruto","mean_sueldo_neto","mean_deduccion_total","pct_deduccion_sobre_bruto"]},"enigh_jubilaciones_actuales":{"type":"object","properties":{"unit_trim":{"type":"string"},"unit_mes":{"type":"string"},"pct_hogares_con_jubilacion":{"type":"number"},"mean_jubilacion_sobre_todos_trim":{"type":"number"},"mean_jubilacion_solo_jubilados_trim":{"type":"number"},"mean_jubilacion_solo_jubilados_mensual":{"type":"number"},"n_hogares_con_jubilacion_expandido":{"type":"integer"}},"required":["unit_trim","unit_mes","pct_hogares_con_jubilacion","mean_jubilacion_sobre_todos_trim","mean_jubilacion_solo_jubilados_trim","mean_jubilacion_solo_jubilados_mensual","n_hogares_con_jubilacion_expandido"]},"interpretacion":{"type":"string"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["cdmx_aportes_actuales","enigh_jubilaciones_actuales","interpretacion","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/actividad-cdmx-vs-nacional":{"get":{"tags":["comparativo"],"operationId":"actividad_cdmx_vs_nacional_api_v1_comparativo_actividad_cdmx_vs_nacional_get","summary":"Actividad Cdmx Vs Nacional","description":"Contraste urbano/rural: % hogares con actividad agro y no-agro en CDMX vs nacional.\n\nEsperable: CDMX << nacional en agro (9.64% nacional, memory indica residuos\nperiurbanos Milpa Alta/Tláhuac/Xochimilco en CDMX); CDMX >= nacional en noagro\n(22.77% nacional; CDMX es metrópoli comercial con mayor actividad\nno-agropecuaria por hogar).","responses":{"200":{"description":"Comparativo actividades de hogares CDMX vs nacional (agro / noagro / jcf).","content":{"application/json":{"schema":{"type":"object","properties":{"agro":{"type":"object","properties":{"tipo":{"type":"string"},"hogares_expandido_nacional":{"type":"integer"},"hogares_expandido_cdmx":{"type":"integer"},"pct_nacional":{"type":"number"},"pct_cdmx":{"type":"number"},"ratio_cdmx_sobre_nacional":{"type":"number"}},"required":["tipo","hogares_expandido_nacional","hogares_expandido_cdmx","pct_nacional","pct_cdmx","ratio_cdmx_sobre_nacional"]},"noagro":{"type":"object","properties":{"tipo":{"type":"string"},"hogares_expandido_nacional":{"type":"integer"},"hogares_expandido_cdmx":{"type":"integer"},"pct_nacional":{"type":"number"},"pct_cdmx":{"type":"number"},"ratio_cdmx_sobre_nacional":{"type":"number"}},"required":["tipo","hogares_expandido_nacional","hogares_expandido_cdmx","pct_nacional","pct_cdmx","ratio_cdmx_sobre_nacional"]},"n_hogares_total_nacional":{"type":"integer"},"n_hogares_total_cdmx":{"type":"integer"},"note":{"type":"string"},"nota_hipotesis":{"type":"string"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["agro","noagro","n_hogares_total_nacional","n_hogares_total_cdmx","note","nota_hipotesis","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/gastos/cdmx-vs-nacional":{"get":{"tags":["comparativo"],"operationId":"gastos_cdmx_vs_nacional_api_v1_comparativo_gastos_cdmx_vs_nacional_get","summary":"Gastos Cdmx Vs Nacional","description":"Gasto mensual por rubro — los 9 rubros INEGI oficiales — CDMX vs nacional.\n\nDevuelve mean mensual por rubro en ambos scopes y delta absoluto + relativo,\nmás estructura de gasto (%) de cada rubro sobre el gasto monetario total.","responses":{"200":{"description":"Comparativo gastos rubro a rubro CDMX vs nacional ENIGH.","content":{"application/json":{"schema":{"type":"object","properties":{"mean_gasto_mon_mensual_nacional":{"type":"number"},"mean_gasto_mon_mensual_cdmx":{"type":"number"},"rubros":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"mean_cdmx_mensual":{"type":"number"},"mean_nacional_mensual":{"type":"number"},"delta_absoluto":{"type":"number"},"delta_pct":{"type":"number"},"pct_del_monetario_cdmx":{"type":"number"},"pct_del_monetario_nacional":{"type":"number"}},"required":["slug","nombre","mean_cdmx_mensual","mean_nacional_mensual","delta_absoluto","delta_pct","pct_del_monetario_cdmx","pct_del_monetario_nacional"]}},"note":{"type":"string"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["mean_gasto_mon_mensual_nacional","mean_gasto_mon_mensual_cdmx","rubros","note","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/bancarizacion":{"get":{"tags":["comparativo"],"operationId":"bancarizacion_api_v1_comparativo_bancarizacion_get","summary":"Bancarizacion","description":"Uso de tarjeta (crédito o débito) en trimestre — CDMX vs nacional.\n\nDefinición operativa: \"hogar con ≥1 registro en enigh.gastotarjetas en\nel trimestre de referencia\". NO mide posesión de tarjeta, solo uso\nefectivo en trimestre; captura débito + crédito indistintamente.","responses":{"200":{"description":"Bancarización (% hogares con cuenta) CDMX vs nacional. Cifra nacional corregida 7.1→8.87% en S7.","content":{"application/json":{"schema":{"type":"object","properties":{"definicion_operativa":{"type":"string"},"n_hogares_expandido_nacional":{"type":"integer"},"n_hogares_expandido_cdmx":{"type":"integer"},"hogares_con_uso_tarjeta_nacional":{"type":"integer"},"hogares_con_uso_tarjeta_cdmx":{"type":"integer"},"pct_nacional":{"type":"number"},"pct_cdmx":{"type":"number"},"delta_pp":{"type":"number"},"ratio_cdmx_sobre_nacional":{"type":"number"},"caveats":{"type":"array","items":{"type":"string"}}},"required":["definicion_operativa","n_hogares_expandido_nacional","n_hogares_expandido_cdmx","hogares_con_uso_tarjeta_nacional","hogares_con_uso_tarjeta_cdmx","pct_nacional","pct_cdmx","delta_pp","ratio_cdmx_sobre_nacional","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/comparativo/top-vs-bottom":{"get":{"tags":["comparativo"],"operationId":"top_vs_bottom_api_v1_comparativo_top_vs_bottom_get","summary":"Top Vs Bottom","description":"Extremos CDMX (p1/p5/p10 vs p90/p95/p99) mapeados contra ENIGH d1 y d10.\n\nMuestra el rango completo de la brecha entre servidores públicos CDMX y la\ndistribución nacional de ingresos hogar. Insight central esperable:\nincluso el p99 CDMX (top 1% servidores) está debajo del mean mensual d10\nnacional — la distribución CDMX está comprimida respecto a la distribución\nnacional hogar (última incluye transferencias + rentas + múltiples perceptores).","responses":{"200":{"description":"Comparativo d10 nacional vs decil más alto CDMX (top puestos).","content":{"application/json":{"schema":{"type":"object","properties":{"top_bracket":{"type":"object","additionalProperties":{}},"bottom_bracket":{"type":"object","additionalProperties":{}},"narrative":{"type":"string"},"insights":{"type":"array","items":{"type":"string"}},"caveats":{"type":"array","items":{"type":"string"}}},"required":["top_bracket","bottom_bracket","narrative","insights","caveats"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/servidores/":{"get":{"tags":["servidores"],"operationId":"list_servidores_api_v1_servidores__get","summary":"Listar servidores con filtros y paginación","description":"Lista paginada de servidores del padrón CDMX (246K registros). Soporta filtros por `sector_id`, `sexo`, rango de edad, rango de sueldo, `tipo_contratacion_id`, `tipo_personal_id`, `universo_id`, y `puesto_search` (búsqueda ILIKE sobre el nombre del puesto). Cache HTTP `public, max-age=300`.","parameters":[{"schema":{"type":"integer"},"required":false,"name":"sector_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sexo","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_min","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_max","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_min","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_max","in":"query"},{"schema":{"type":"string"},"required":false,"name":"puesto_search","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_contratacion_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_personal_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"universo_id","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"},{"schema":{"type":"string","default":"id"},"required":false,"name":"order_by","in":"query"},{"schema":{"type":"string","default":"asc"},"required":false,"name":"order","in":"query"}],"responses":{"200":{"description":"Página de servidores.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"apellido_1":{"type":"string"},"apellido_2":{"type":["string","null"]},"sexo":{"type":"string"},"edad":{"type":["integer","null"]},"sueldo_bruto":{"type":["string","null"]},"sueldo_neto":{"type":["string","null"]},"sector":{"type":["string","null"]},"puesto":{"type":["string","null"]}},"required":["id","nombre","apellido_1","apellido_2","sexo","edad","sueldo_bruto","sueldo_neto","sector","puesto"]}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"pages":{"type":"integer"}},"required":["data","total","page","per_page","pages"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/servidores/stats":{"get":{"tags":["servidores"],"operationId":"servidor_stats_api_v1_servidores_stats_get","summary":"Estadísticas agregadas con filtros (panel reactivo)","description":"Estadísticas sobre el subconjunto del padrón que matchea los filtros recibidos: total, promedio, mediana, percentiles (p25/p75), min/max de sueldo bruto, promedio de neto y edad, desglose por género con brecha %, y distribución por rangos de sueldo (`0-5K`, `5K-10K`, ..., `120K+`). Es el endpoint que alimenta el panel de filtros reactivo del laboratorio público. Cache HTTP `public, max-age=300`.","parameters":[{"schema":{"type":"integer"},"required":false,"name":"sector_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sexo","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_min","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_max","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_min","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_max","in":"query"},{"schema":{"type":"string"},"required":false,"name":"puesto_search","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_contratacion_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_personal_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"universo_id","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"},{"schema":{"type":"string","default":"id"},"required":false,"name":"order_by","in":"query"},{"schema":{"type":"string","default":"asc"},"required":false,"name":"order","in":"query"}],"responses":{"200":{"description":"Stats agregadas del subconjunto filtrado.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"sueldo_bruto_avg":{"type":["number","null"]},"sueldo_bruto_median":{"type":["number","null"]},"sueldo_bruto_p25":{"type":["number","null"]},"sueldo_bruto_p75":{"type":["number","null"]},"sueldo_bruto_min":{"type":["number","null"]},"sueldo_bruto_max":{"type":["number","null"]},"sueldo_neto_avg":{"type":["number","null"]},"edad_avg":{"type":["number","null"]},"count_hombres":{"type":"integer"},"count_mujeres":{"type":"integer"},"brecha_genero_pct":{"type":["number","null"]},"distribucion_sueldo":{"type":"array","items":{"type":"object","properties":{"rango":{"type":"string"},"count":{"type":"integer"}},"required":["rango","count"]}}},"required":["total","sueldo_bruto_avg","sueldo_bruto_median","sueldo_bruto_p25","sueldo_bruto_p75","sueldo_bruto_min","sueldo_bruto_max","sueldo_neto_avg","edad_avg","count_hombres","count_mujeres","brecha_genero_pct","distribucion_sueldo"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/servidores/{servidor_id}":{"get":{"tags":["servidores"],"operationId":"get_servidor_api_v1_servidores__servidor_id__get","summary":"Detalle de un servidor por ID","description":"Detalle completo de un servidor (persona) por su ID numérico: datos personales, sueldo bruto/neto, fecha de ingreso, nivel salarial, sector, puesto, tipos de contratación/personal/nómina y universo. Cache HTTP `public, max-age=300`.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"servidor_id","in":"path"}],"responses":{"200":{"description":"Detalle del servidor.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"apellido_1":{"type":"string"},"apellido_2":{"type":["string","null"]},"sexo":{"type":"string"},"edad":{"type":["integer","null"]},"sueldo_bruto":{"type":["string","null"]},"sueldo_neto":{"type":["string","null"]},"fecha_ingreso":{"type":["string","null"]},"id_nivel_salarial":{"type":["integer","null"]},"sector":{"type":["string","null"]},"puesto":{"type":["string","null"]},"tipo_contratacion":{"type":["string","null"]},"tipo_personal":{"type":["string","null"]},"tipo_nomina":{"type":["string","null"]},"universo":{"type":["string","null"]}},"required":["id","nombre","apellido_1","apellido_2","sexo","edad","sueldo_bruto","sueldo_neto","fecha_ingreso","id_nivel_salarial","sector","puesto","tipo_contratacion","tipo_personal","tipo_nomina","universo"]}}}},"404":{"description":"`servidor_id` no existe en `cdmx.personas`.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/sectores/":{"get":{"tags":["sectores"],"operationId":"list_sectores_api_v1_sectores__get","summary":"Listar los 73 sectores del padrón CDMX con estadísticas","description":"Devuelve los 73 sectores con conteo de nombramientos, sueldo bruto promedio, y desglose hombres/mujeres por sector. Ordenado alfabéticamente. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista de sectores con stats agregadas.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"total_servidores":{"type":"integer"},"sueldo_bruto_avg":{"type":["number","null"]},"count_hombres":{"type":"integer"},"count_mujeres":{"type":"integer"}},"required":["id","nombre","total_servidores","sueldo_bruto_avg","count_hombres","count_mujeres"]}}}}},"429":{"description":"Rate limit excedido (30 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/sectores/compare":{"get":{"tags":["sectores"],"operationId":"compare_sectores_api_v1_sectores_compare_get","summary":"Comparar dos sectores lado a lado","description":"Devuelve el detalle estadístico completo (sueldo promedio, mediana, percentiles, top 10 puestos, brecha de género) para dos sectores identificados por su `id`. Útil para visualizaciones comparativas. Si cualquiera de los dos sectores no existe, devuelve `404` (el primer raise gana — `a` antes que `b`). Cache HTTP `public, max-age=3600`.","parameters":[{"schema":{"type":"integer","description":"ID del sector A"},"required":true,"description":"ID del sector A","name":"a","in":"query"},{"schema":{"type":"integer","description":"ID del sector B"},"required":true,"description":"ID del sector B","name":"b","in":"query"}],"responses":{"200":{"description":"Comparación lado a lado de dos sectores.","content":{"application/json":{"schema":{"type":"object","properties":{"sector_a":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"total_servidores":{"type":"integer"},"sueldo_bruto_avg":{"type":["number","null"]},"sueldo_bruto_median":{"type":["number","null"]},"sueldo_neto_avg":{"type":["number","null"]},"edad_avg":{"type":["number","null"]},"count_hombres":{"type":"integer"},"count_mujeres":{"type":"integer"},"brecha_genero_pct":{"type":["number","null"]},"top_puestos":{"type":"array","items":{"type":"object","properties":{"puesto":{"type":"string"},"count":{"type":"integer"},"sueldo_avg":{"type":["number","null"]}},"required":["puesto","count","sueldo_avg"]}}},"required":["id","nombre","total_servidores","sueldo_bruto_avg","sueldo_bruto_median","sueldo_neto_avg","edad_avg","count_hombres","count_mujeres","brecha_genero_pct","top_puestos"]},"sector_b":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"total_servidores":{"type":"integer"},"sueldo_bruto_avg":{"type":["number","null"]},"sueldo_bruto_median":{"type":["number","null"]},"sueldo_neto_avg":{"type":["number","null"]},"edad_avg":{"type":["number","null"]},"count_hombres":{"type":"integer"},"count_mujeres":{"type":"integer"},"brecha_genero_pct":{"type":["number","null"]},"top_puestos":{"type":"array","items":{"type":"object","properties":{"puesto":{"type":"string"},"count":{"type":"integer"},"sueldo_avg":{"type":["number","null"]}},"required":["puesto","count","sueldo_avg"]}}},"required":["id","nombre","total_servidores","sueldo_bruto_avg","sueldo_bruto_median","sueldo_neto_avg","edad_avg","count_hombres","count_mujeres","brecha_genero_pct","top_puestos"]}},"required":["sector_a","sector_b"]}}}},"404":{"description":"Uno o ambos `sector_id` no existen en `cdmx.cat_sectores`.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (15 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/sectores/{sector_id}/stats":{"get":{"tags":["sectores"],"operationId":"sector_stats_api_v1_sectores__sector_id__stats_get","summary":"Detalle estadístico de un sector","description":"Detalle completo de un sector identificado por `sector_id`: totales, promedio y mediana de sueldo bruto, percentiles, promedio de edad, desglose por género (con brecha %), y top 10 puestos del sector con su sueldo promedio. Cache HTTP `public, max-age=3600`.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"sector_id","in":"path"}],"responses":{"200":{"description":"Detalle completo del sector.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"total_servidores":{"type":"integer"},"sueldo_bruto_avg":{"type":["number","null"]},"sueldo_bruto_median":{"type":["number","null"]},"sueldo_neto_avg":{"type":["number","null"]},"edad_avg":{"type":["number","null"]},"count_hombres":{"type":"integer"},"count_mujeres":{"type":"integer"},"brecha_genero_pct":{"type":["number","null"]},"top_puestos":{"type":"array","items":{"type":"object","properties":{"puesto":{"type":"string"},"count":{"type":"integer"},"sueldo_avg":{"type":["number","null"]}},"required":["puesto","count","sueldo_avg"]}}},"required":["id","nombre","total_servidores","sueldo_bruto_avg","sueldo_bruto_median","sueldo_neto_avg","edad_avg","count_hombres","count_mujeres","brecha_genero_pct","top_puestos"]}}}},"404":{"description":"`sector_id` no existe en `cdmx.cat_sectores`.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (30 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/tipos-contratacion":{"get":{"tags":["catalogos"],"operationId":"tipos_contratacion_api_v1_catalogos_tipos_contratacion_get","summary":"Catálogo de tipos de contratación con conteo de uso","description":"Devuelve los tipos de contratación del padrón CDMX (Base, Honorarios, Eventual, etc.) con el conteo de nombramientos que referencian cada uno. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/tipos-personal":{"get":{"tags":["catalogos"],"operationId":"tipos_personal_api_v1_catalogos_tipos_personal_get","summary":"Catálogo de tipos de personal con conteo de uso","description":"Devuelve los tipos de personal (Operativo, Mando, etc.) con conteo de nombramientos por tipo. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/tipos-nomina":{"get":{"tags":["catalogos"],"operationId":"tipos_nomina_api_v1_catalogos_tipos_nomina_get","summary":"Catálogo de tipos de nómina con conteo de uso","description":"Devuelve los tipos de nómina identificados por la columna `clave` (integer, NO `nombre` como los otros catálogos) con conteo de uso. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/universos":{"get":{"tags":["catalogos"],"operationId":"universos_api_v1_catalogos_universos_get","summary":"Catálogo de universos con conteo de uso","description":"Devuelve los universos del padrón CDMX (agrupaciones administrativas) con conteo de nombramientos por universo. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/sectores":{"get":{"tags":["catalogos"],"operationId":"sectores_api_v1_catalogos_sectores_get","summary":"Catálogo de los 73 sectores con conteo de uso","description":"Devuelve los 73 sectores del padrón CDMX con conteo de nombramientos por sector, ordenados alfabéticamente. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/sexos":{"get":{"tags":["catalogos"],"operationId":"sexos_api_v1_catalogos_sexos_get","summary":"Catálogo de sexos con conteo de uso","description":"Devuelve el catálogo `cat_sexos` (MASCULINO, FEMENINO, no especificado) con conteo de personas por valor. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/niveles-salariales":{"get":{"tags":["catalogos"],"operationId":"niveles_salariales_api_v1_catalogos_niveles_salariales_get","summary":"Catálogo de niveles salariales con conteo de uso","description":"Devuelve los niveles salariales identificados por `clave` con conteo de nombramientos por nivel. Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Lista del catálogo con conteo de uso.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/catalogos/puestos":{"get":{"tags":["catalogos"],"operationId":"puestos_api_v1_catalogos_puestos_get","summary":"Catálogo paginado de puestos con búsqueda","description":"Devuelve los 1 772 puestos del padrón CDMX paginados, con conteo de nombramientos por puesto. Soporta búsqueda ILIKE vía `search`. Ordenado por conteo descendente. Cache HTTP `public, max-age=3600`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"search","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"}],"responses":{"200":{"description":"Página del catálogo de puestos.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"count":{"type":"integer"}},"required":["id","nombre","count"]}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"pages":{"type":"integer"}},"required":["data","total","page","per_page","pages"]}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/dashboard/stats":{"get":{"tags":["dashboard"],"operationId":"dashboard_stats_api_v1_dashboard_stats_get","summary":"Snapshot agregado del padrón CDMX","description":"Devuelve un snapshot completo del dataset de servidores públicos de la CDMX (246K nombramientos): totales, percentiles salariales (p25/p50/p75/p90), distribuciones por sueldo / edad / contratación / tipo de personal, top 15 sectores, brecha de género por sector (top 10 por magnitud absoluta), posiciones más frecuentes, distribución de antigüedad, y desglose bruto vs neto por rango. Las cifras provienen mayoritariamente de las cinco materialized views `cdmx.mv_dashboard_*` (refresco vía `POST /api/v1/admin/refresh-materialized-views`). Cache HTTP `public, max-age=3600`.","responses":{"200":{"description":"Snapshot completo del padrón CDMX.","content":{"application/json":{"schema":{"type":"object","properties":{"totalServidores":{"type":"integer"},"totalSectors":{"type":"integer"},"avgSalary":{"type":"number"},"medianSalary":{"type":"number"},"minSalary":{"type":"number"},"maxSalary":{"type":"number"},"p25":{"type":"number"},"p50":{"type":"number"},"p75":{"type":"number"},"p90":{"type":"number"},"genderGapPercent":{"type":"number"},"hombres":{"type":"integer"},"mujeres":{"type":"integer"},"avgSalaryMale":{"type":"number"},"avgSalaryFemale":{"type":"number"},"salaryDistribution":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer"}},"required":["label","count"]}},"ageDistribution":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer"}},"required":["label","count"]}},"contractTypes":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer"}},"required":["label","count"]}},"personalTypes":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer"}},"required":["label","count"]}},"salaryByAge":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"avg":{"type":"number"}},"required":["label","avg"]}},"top15Sectors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"},"avgSalary":{"type":"number"},"avgMale":{"type":"number"},"avgFemale":{"type":"number"}},"required":["name","count","avgSalary","avgMale","avgFemale"]}},"allSectors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"},"avgSalary":{"type":"number"},"avgMale":{"type":"number"},"avgFemale":{"type":"number"}},"required":["name","count","avgSalary","avgMale","avgFemale"]}},"genderGapBySector":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"avgMale":{"type":"number"},"avgFemale":{"type":"number"},"gap":{"type":"number"}},"required":["name","avgMale","avgFemale","gap"]}},"topPositions":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"count":{"type":"integer"},"avgSalary":{"type":"number"}},"required":["name","count","avgSalary"]}},"seniorityDistribution":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"count":{"type":"integer"}},"required":["label","count"]}},"salaryBySeniority":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"avg":{"type":"number"},"count":{"type":"integer"}},"required":["label","avg","count"]}},"avgSeniority":{"type":"number"},"avgNetSalary":{"type":"number"},"avgDeduction":{"type":"number"},"avgDeductionPercent":{"type":"number"},"brutoNetoByRange":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"avgBruto":{"type":"number"},"avgNeto":{"type":"number"},"count":{"type":"integer"}},"required":["label","avgBruto","avgNeto","count"]}}},"required":["totalServidores","totalSectors","avgSalary","medianSalary","minSalary","maxSalary","p25","p50","p75","p90","genderGapPercent","hombres","mujeres","avgSalaryMale","avgSalaryFemale","salaryDistribution","ageDistribution","contractTypes","personalTypes","salaryByAge","top15Sectors","allSectors","genderGapBySector","topPositions","seniorityDistribution","salaryBySeniority","avgSeniority","avgNetSalary","avgDeduction","avgDeductionPercent","brutoNetoByRange"]}}}},"429":{"description":"Rate limit excedido (10 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/analytics/puestos/ranking":{"get":{"tags":["analytics"],"operationId":"puestos_ranking_api_v1_analytics_puestos_ranking_get","summary":"Top puestos por sueldo promedio (RANK + PERCENT_RANK + LAG)","description":"Top puestos del padrón CDMX ordenados por sueldo bruto promedio descendente. Cada fila incluye `rank` (RANK), `percent_rank` (PERCENT_RANK normalizado 0..1) y `gap_vs_next` (diferencia absoluta vs el sueldo del puesto anterior — útil para detectar saltos discontinuos en la curva). Filtro implícito: sólo puestos con `COUNT(*) >= 5` para evitar outliers de un solo nombramiento. Cache HTTP `public, max-age=900`.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Lista rankeada de puestos.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"puesto_id":{"type":"integer"},"nombre":{"type":"string"},"avg_sueldo":{"type":"number"},"count":{"type":"integer"},"rank":{"type":"integer"},"percent_rank":{"type":"number"},"gap_vs_next":{"type":["number","null"]}},"required":["puesto_id","nombre","avg_sueldo","count","rank","percent_rank","gap_vs_next"]}}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/analytics/sectores/ranking":{"get":{"tags":["analytics"],"operationId":"sectores_ranking_api_v1_analytics_sectores_ranking_get","summary":"Sectores rankeados por sueldo promedio (con desviación vs media global)","description":"Los 73 sectores del padrón CDMX rankeados por sueldo bruto promedio descendente. Cada fila incluye `avg_vs_global_pct` (desviación porcentual del sector respecto al promedio global computado con `AVG() OVER ()`), útil para identificar sectores atípicos por encima o debajo de la media institucional. Cache HTTP `public, max-age=900`.","responses":{"200":{"description":"Lista rankeada de los 73 sectores.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"sector_id":{"type":"integer"},"nombre":{"type":"string"},"avg_sueldo":{"type":"number"},"count":{"type":"integer"},"rank":{"type":"integer"},"percent_rank":{"type":"number"},"avg_vs_global_pct":{"type":"number"}},"required":["sector_id","nombre","avg_sueldo","count","rank","percent_rank","avg_vs_global_pct"]}}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/analytics/brecha-edad":{"get":{"tags":["analytics"],"operationId":"brecha_edad_api_v1_analytics_brecha_edad_get","summary":"Brecha salarial por grupo etario (con referencia global)","description":"Brecha salarial hombre/mujer (`gap_pct = (avg_male - avg_female) / avg_female * 100`) por bucket de edad: `18-25`, `26-35`, `36-45`, `46-55`, `56+`. Devuelve también `running_avg_global` (promedio del padrón completo replicado en cada fila, vía `AVG() OVER ()`) para que el consumidor compare cada bucket con el promedio global sin emitir un request adicional. Cache HTTP `public, max-age=900`.","responses":{"200":{"description":"Brecha por grupo etario (5 buckets).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"bucket_edad":{"type":"string"},"avg_male":{"type":["number","null"]},"avg_female":{"type":["number","null"]},"count_male":{"type":"integer"},"count_female":{"type":"integer"},"gap_pct":{"type":["number","null"]},"running_avg_global":{"type":"number"}},"required":["bucket_edad","avg_male","avg_female","count_male","count_female","gap_pct","running_avg_global"]}}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/personas/":{"get":{"tags":["personas"],"operationId":"list_personas_api_v1_personas__get","summary":"Listar personas del padrón con paginación y búsqueda","description":"[Uso interno administrativo] Lista paginada de personas del padrón CDMX. Soporta filtros por `nombre` (ILIKE sobre nombre, apellido_1 y apellido_2 simultáneamente) y `sexo_id`. Requiere JWT admin. El SDK Python `datos-mexico` no expone este endpoint por ser operacional, no analítico.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nombre","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"sexo_id","in":"query"}],"responses":{"200":{"description":"Página de personas.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"apellido_1":{"type":"string"},"apellido_2":{"type":["string","null"],"default":null},"sexo_id":{"type":["integer","null"],"default":null},"edad":{"type":["integer","null"],"default":null}},"required":["id","nombre","apellido_1"]}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"pages":{"type":"integer"}},"required":["data","total","page","per_page","pages"]}}}},"429":{"description":"Rate limit excedido (30 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/personas/{persona_id}":{"get":{"tags":["personas"],"operationId":"get_persona_api_v1_personas__persona_id__get","summary":"Detalle de una persona por ID","description":"[Uso interno administrativo] Detalle de una persona del padrón por su ID numérico. Requiere JWT admin. El SDK Python `datos-mexico` no expone este endpoint por ser operacional, no analítico.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"persona_id","in":"path"}],"responses":{"200":{"description":"Detalle de persona.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre":{"type":"string"},"apellido_1":{"type":"string"},"apellido_2":{"type":["string","null"],"default":null},"sexo_id":{"type":["integer","null"],"default":null},"edad":{"type":["integer","null"],"default":null}},"required":["id","nombre","apellido_1"]}}}},"404":{"description":"`persona_id` no existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/nombramientos/":{"get":{"tags":["nombramientos"],"operationId":"list_nombramientos_api_v1_nombramientos__get","summary":"Listar nombramientos con paginación y filtros","description":"[Uso interno administrativo] Lista paginada de nombramientos. Soporta filtros por `persona_id` y `sector_id`. Requiere JWT admin. El SDK Python `datos-mexico` no expone este endpoint por ser operacional, no analítico.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"persona_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"sector_id","in":"query"}],"responses":{"200":{"description":"Página de nombramientos.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"persona_id":{"type":"integer"},"puesto_id":{"type":["integer","null"],"default":null},"sector_id":{"type":["integer","null"],"default":null},"tipo_nomina_id":{"type":["integer","null"],"default":null},"tipo_contratacion_id":{"type":["integer","null"],"default":null},"tipo_personal_id":{"type":["integer","null"],"default":null},"universo_id":{"type":["integer","null"],"default":null},"nivel_salarial_id":{"type":["integer","null"],"default":null},"fecha_ingreso":{"type":["string","null"],"default":null},"sueldo_bruto":{"type":["string","null"],"default":null},"sueldo_neto":{"type":["string","null"],"default":null}},"required":["id","persona_id"]}},"total":{"type":"integer"},"page":{"type":"integer"},"per_page":{"type":"integer"},"pages":{"type":"integer"}},"required":["data","total","page","per_page","pages"]}}}},"429":{"description":"Rate limit excedido (30 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/nombramientos/{nombramiento_id}":{"get":{"tags":["nombramientos"],"operationId":"get_nombramiento_api_v1_nombramientos__nombramiento_id__get","summary":"Detalle de un nombramiento por ID","description":"[Uso interno administrativo] Detalle de un nombramiento por su ID numérico. Requiere JWT admin. El SDK Python `datos-mexico` no expone este endpoint por ser operacional, no analítico.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"nombramiento_id","in":"path"}],"responses":{"200":{"description":"Detalle de nombramiento.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"persona_id":{"type":"integer"},"puesto_id":{"type":["integer","null"],"default":null},"sector_id":{"type":["integer","null"],"default":null},"tipo_nomina_id":{"type":["integer","null"],"default":null},"tipo_contratacion_id":{"type":["integer","null"],"default":null},"tipo_personal_id":{"type":["integer","null"],"default":null},"universo_id":{"type":["integer","null"],"default":null},"nivel_salarial_id":{"type":["integer","null"],"default":null},"fecha_ingreso":{"type":["string","null"],"default":null},"sueldo_bruto":{"type":["string","null"],"default":null},"sueldo_neto":{"type":["string","null"],"default":null}},"required":["id","persona_id"]}}}},"404":{"description":"`nombramiento_id` no existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/export/csv":{"get":{"tags":["export"],"operationId":"export_csv_api_v1_export_csv_get","summary":"Exportar nombramientos CDMX en CSV (≤ 50 000 filas)","description":"Exporta hasta 50 000 filas del padrón CDMX en formato CSV (`text/csv`, `Content-Disposition: attachment`) con los mismos filtros que `GET /api/v1/servidores/`. Columnas: `id`, `nombre`, `apellido_1`, `apellido_2`, `sexo`, `edad`, `sueldo_bruto`, `sueldo_neto`, `fecha_ingreso`, `sector`, `puesto`, `tipo_contratacion`, `tipo_personal`, `tipo_nomina`, `universo`. Para exports más grandes consumir paginado vía `/api/v1/servidores/`. Rate limit estricto (5/min/IP) — endpoint diseñado para descarga puntual, no para bulk extraction continua.","parameters":[{"schema":{"type":"integer"},"required":false,"name":"sector_id","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sexo","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_min","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"edad_max","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_min","in":"query"},{"schema":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$"}]},"required":false,"name":"sueldo_max","in":"query"},{"schema":{"type":"string"},"required":false,"name":"puesto_search","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_contratacion_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"tipo_personal_id","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"universo_id","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"per_page","in":"query"},{"schema":{"type":"string","default":"id"},"required":false,"name":"order_by","in":"query"},{"schema":{"type":"string","default":"asc"},"required":false,"name":"order","in":"query"}],"responses":{"200":{"description":"Stream CSV con headers de descarga.","content":{"text/csv":{"schema":{"type":"string"}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/health":{"get":{"tags":["enoe"],"operationId":"get_enoe_health_api_v1_enoe_health_get","summary":"Status operacional del dataset ENOE","description":"Verifica conectividad a la base de datos, último periodo cargado, timestamp de la última carga exitosa y totales de microdatos + indicadores agregados. Si la base no es alcanzable retorna HTTP 503. Los counts provienen de la tabla pre-computada `enoe.estadisticas_globales` (refrescada al final de cada script ETL — migration 033).","responses":{"200":{"description":"Servicio ENOE operativo.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"ultimo_periodo":{"type":["string","null"]},"ultima_carga":{"type":["string","null"]},"total_microdatos":{"type":"integer"},"total_indicadores_agregados":{"type":"integer"},"cobertura_temporal":{"type":["string","null"]}},"required":["status","ultimo_periodo","ultima_carga","total_microdatos","total_indicadores_agregados","cobertura_temporal"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"503":{"description":"Base de datos no alcanzable."}}}},"/api/v1/enoe/metadata":{"get":{"tags":["enoe"],"operationId":"get_enoe_metadata_api_v1_enoe_metadata_get","summary":"Metadata completa del dataset ENOE","description":"Información sobre fuente, periodicidad, cobertura temporal y geográfica, tablas disponibles con conteo de filas y `status` de disponibilidad, etapas metodológicas y caveats interpretativos. Los counts provienen de la tabla pre-computada `enoe.estadisticas_globales` (migration 033).\n\n**Sobre `tablas_disponibles[].status`**: el campo señaliza la disponibilidad efectiva de cada tabla del schema:\n- `available` — tabla con datos ingestados.\n- `schema-ready` — tabla creada pero aún sin datos (roadmap futuro). Las tablas `indicadores_area_metropolitana` e `indicadores_anuales_ampliado` están en este estado: schema completo, ingesta posterior pendiente. Cualquier endpoint que intente consumirlas regresará respuestas vacías hasta entonces.\n- `deprecated` — reservado para uso futuro.\n\nEl booleano `has_data` se mantiene por compatibilidad con consumidores existentes; es derivable de `status` (`status == 'available'` ⇔ `has_data is True`).","responses":{"200":{"description":"Metadata completa del dataset ENOE.","content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string"},"acronimo":{"type":"string"},"fuente":{"type":"string"},"fuente_url":{"type":"string"},"periodicidad":{"type":"string"},"cobertura_temporal":{"type":"string"},"cobertura_geografica":{"type":"string"},"n_trimestres_disponibles":{"type":"integer"},"n_indicadores":{"type":"integer"},"n_entidades":{"type":"integer"},"etapas_metodologicas":{"type":"array","items":{"type":"string"}},"tablas_disponibles":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"descripcion":{"type":"string"},"n_filas":{"type":"integer"},"has_data":{"type":"boolean"},"status":{"type":"string","enum":["available","schema-ready","deprecated"],"default":"available"}},"required":["nombre","descripcion","n_filas","has_data"]}},"total_microdatos":{"type":"integer"},"total_agregados":{"type":"integer"},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"sources":{"type":"array","items":{"type":"string"}},"last_updated":{"type":["string","null"]}},"required":["nombre","acronimo","fuente","fuente_url","periodicidad","cobertura_temporal","cobertura_geografica","n_trimestres_disponibles","n_indicadores","n_entidades","etapas_metodologicas","tablas_disponibles","total_microdatos","total_agregados","caveats","sources","last_updated"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/catalogos/indicadores":{"get":{"tags":["enoe"],"operationId":"get_catalogo_indicadores_api_v1_enoe_catalogos_indicadores_get","summary":"Catálogo de los 13 indicadores disponibles","description":"Lista los 13 indicadores del observatorio (8 conteos poblacionales + 5 tasas) con su fórmula INEGI (Reconstrucción de variables 2023), cobertura temporal observada y caveat metodológico aplicable. Reutilizable como fuente para dropdowns en el frontend.","responses":{"200":{"description":"Catálogo de 13 indicadores con cobertura.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"indicadores":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"descripcion":{"type":"string"},"unidad":{"type":"string"},"categoria":{"type":"string"},"formula":{"type":"string"},"fuente_metodologica":{"type":"string"},"n_observaciones_nacional":{"type":"integer"},"n_observaciones_entidad":{"type":"integer"},"cobertura_temporal":{"type":"string"},"caveat_metodologico":{"type":["string","null"],"default":null}},"required":["slug","nombre","descripcion","unidad","categoria","formula","fuente_metodologica","n_observaciones_nacional","n_observaciones_entidad","cobertura_temporal"]}},"source":{"type":"string"}},"required":["count","indicadores","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/catalogos/entidades":{"get":{"tags":["enoe"],"operationId":"get_catalogo_entidades_api_v1_enoe_catalogos_entidades_get","summary":"Catálogo de las 32 entidades federativas","description":"Lista las 32 entidades federativas de México con clave AGEE INEGI 2020 (CHAR(2) '01'..'32'), nombre oficial y abreviatura usada en boletines INEGI. Replica el catálogo de enigh.cat_entidad.","responses":{"200":{"description":"32 entidades federativas.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"entidades":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"abreviatura":{"type":["string","null"],"default":null}},"required":["clave","nombre"]}},"source":{"type":"string"}},"required":["count","entidades","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/catalogos/etapas-metodologicas":{"get":{"tags":["enoe"],"operationId":"get_catalogo_etapas_api_v1_enoe_catalogos_etapas_metodologicas_get","summary":"Catálogo de las 3 etapas metodológicas del ENOE","description":"Las 3 etapas metodológicas que conviven en la serie histórica: clasica (2005T1-2020T1, marco pre-Censo 2020), etoe_telefonica (solo 2020T2, sin microdatos), y enoe_n (2020T3-presente, marco post-Censo 2020). Coherente con el ENUM enoe.etapa_metodologica (migration 031).","responses":{"200":{"description":"3 etapas metodológicas con su rango.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"etapas":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"nombre":{"type":"string"},"descripcion":{"type":"string"},"periodo_inicio":{"type":"string"},"periodo_fin":{"type":["string","null"],"default":null},"dominio_edad":{"type":"string"},"n_trimestres":{"type":"integer"},"tiene_microdatos":{"type":"boolean"},"caveat_aplicable":{"type":["string","null"],"default":null}},"required":["slug","nombre","descripcion","periodo_inicio","dominio_edad","n_trimestres","tiene_microdatos"]}},"source":{"type":"string"}},"required":["count","etapas","source"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/indicadores/nacional/serie":{"get":{"tags":["enoe"],"operationId":"get_indicador_nacional_serie_api_v1_enoe_indicadores_nacional_serie_get","summary":"Serie temporal nacional de un indicador","description":"Retorna la serie temporal nacional de un indicador, opcionalmente filtrada por rango de periodos (`desde`/`hasta` en formato YYYYTQ) o etapa metodológica. Caveats inyectados dinámicamente según el indicador y el rango (gap 2020T2, dominio 15+, cambio de marco 2020T3, redefinición TIL1/TCCO).","parameters":[{"schema":{"type":"string","description":"Slug del indicador (ej. tasa_desocupacion)"},"required":true,"description":"Slug del indicador (ej. tasa_desocupacion)","name":"indicador","in":"query"},{"schema":{"type":"string","description":"Periodo inicial YYYYTQ (default: primer punto)"},"required":false,"description":"Periodo inicial YYYYTQ (default: primer punto)","name":"desde","in":"query"},{"schema":{"type":"string","description":"Periodo final YYYYTQ (default: último punto)"},"required":false,"description":"Periodo final YYYYTQ (default: último punto)","name":"hasta","in":"query"},{"schema":{"type":"string","description":"Filtro: clasica | etoe_telefonica | enoe_n"},"required":false,"description":"Filtro: clasica | etoe_telefonica | enoe_n","name":"etapa","in":"query"}],"responses":{"200":{"description":"Serie temporal nacional con caveats inyectados.","content":{"application/json":{"schema":{"type":"object","properties":{"indicador":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":"string"},"categoria":{"type":"string"},"cobertura":{"type":"object","properties":{"desde":{"type":["string","null"]},"hasta":{"type":["string","null"]},"n_observaciones":{"type":"integer"}},"required":["desde","hasta","n_observaciones"]},"datos":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":"string"},"valor":{"type":"number"},"etapa":{"type":"string"}},"required":["periodo","valor","etapa"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"},"source_url":{"type":"string"}},"required":["indicador","nombre","unidad","categoria","cobertura","datos","caveats","source","source_url"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/indicadores/nacional/snapshot":{"get":{"tags":["enoe"],"operationId":"get_indicador_nacional_snapshot_api_v1_enoe_indicadores_nacional_snapshot_get","summary":"Todos los indicadores nacionales en un periodo","description":"Retorna los 13 indicadores nacionales calculados para el periodo indicado (YYYYTQ). HTTP 404 si el periodo no tiene datos (típicamente 2020T2 — sin microdatos por ETOE — o periodos futuros).","parameters":[{"schema":{"type":"string","description":"Periodo YYYYTQ (ej. 2025T1)"},"required":true,"description":"Periodo YYYYTQ (ej. 2025T1)","name":"periodo","in":"query"}],"responses":{"200":{"description":"Snapshot de los 13 indicadores en un periodo.","content":{"application/json":{"schema":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"},"n_indicadores":{"type":"integer"},"indicadores":{"type":"array","items":{"type":"object","properties":{"indicador":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":"string"},"valor":{"type":"number"}},"required":["indicador","nombre","unidad","valor"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["periodo","etapa","n_indicadores","indicadores","caveats","source"]}}}},"404":{"description":"Sin datos para ese periodo (2020T2 gap o periodo futuro).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/indicadores/entidad/serie":{"get":{"tags":["enoe"],"operationId":"get_indicador_entidad_serie_api_v1_enoe_indicadores_entidad_serie_get","summary":"Serie temporal de un indicador para una entidad federativa","description":"Retorna la serie temporal de un indicador para la entidad indicada (`entidad_clave` de 2 dígitos, ej. '09' para CDMX). Filtros opcionales `desde`/`hasta` (YYYYTQ) y `etapa`. HTTP 404 si la entidad no existe.","parameters":[{"schema":{"type":"string","description":"Slug del indicador"},"required":true,"description":"Slug del indicador","name":"indicador","in":"query"},{"schema":{"type":"string","description":"Clave INEGI 2 dígitos (ej. '09' = CDMX)"},"required":true,"description":"Clave INEGI 2 dígitos (ej. '09' = CDMX)","name":"entidad_clave","in":"query"},{"schema":{"type":"string","description":"Periodo inicial YYYYTQ"},"required":false,"description":"Periodo inicial YYYYTQ","name":"desde","in":"query"},{"schema":{"type":"string","description":"Periodo final YYYYTQ"},"required":false,"description":"Periodo final YYYYTQ","name":"hasta","in":"query"},{"schema":{"type":"string","description":"Filtro: clasica | etoe_telefonica | enoe_n"},"required":false,"description":"Filtro: clasica | etoe_telefonica | enoe_n","name":"etapa","in":"query"}],"responses":{"200":{"description":"Serie temporal por entidad federativa.","content":{"application/json":{"schema":{"type":"object","properties":{"indicador":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":"string"},"categoria":{"type":"string"},"entidad_clave":{"type":"string"},"entidad_nombre":{"type":"string"},"entidad_abreviatura":{"type":["string","null"],"default":null},"cobertura":{"type":"object","properties":{"desde":{"type":["string","null"]},"hasta":{"type":["string","null"]},"n_observaciones":{"type":"integer"}},"required":["desde","hasta","n_observaciones"]},"datos":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":"string"},"valor":{"type":"number"},"etapa":{"type":"string"}},"required":["periodo","valor","etapa"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["indicador","nombre","unidad","categoria","entidad_clave","entidad_nombre","cobertura","datos","caveats","source"]}}}},"404":{"description":"`entidad_clave` no existe en el catálogo.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/indicadores/entidad/snapshot":{"get":{"tags":["enoe"],"operationId":"get_indicador_entidad_snapshot_api_v1_enoe_indicadores_entidad_snapshot_get","summary":"Un indicador en un periodo para las 32 entidades federativas","description":"Retorna el valor del indicador para cada una de las 32 entidades en el periodo dado, ordenado por clave AGEE. HTTP 404 si periodo o indicador no tienen datos.","parameters":[{"schema":{"type":"string","description":"Periodo YYYYTQ"},"required":true,"description":"Periodo YYYYTQ","name":"periodo","in":"query"},{"schema":{"type":"string","description":"Slug del indicador"},"required":true,"description":"Slug del indicador","name":"indicador","in":"query"}],"responses":{"200":{"description":"Snapshot por entidad de un indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"},"indicador":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":"string"},"categoria":{"type":"string"},"n_entidades":{"type":"integer"},"datos":{"type":"array","items":{"type":"object","properties":{"entidad_clave":{"type":"string"},"entidad_nombre":{"type":"string"},"entidad_abreviatura":{"type":["string","null"],"default":null},"valor":{"type":"number"}},"required":["entidad_clave","entidad_nombre","valor"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["periodo","etapa","indicador","nombre","unidad","categoria","n_entidades","datos","caveats","source"]}}}},"404":{"description":"Sin datos para ese periodo/indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/indicadores/entidad/ranking":{"get":{"tags":["enoe"],"operationId":"get_indicador_entidad_ranking_api_v1_enoe_indicadores_entidad_ranking_get","summary":"Ranking de entidades por indicador en un periodo","description":"Top N entidades ordenadas por el valor del indicador. `orden=desc` (default) lista de mayor a menor valor (típico para tasa_desocupacion 'peor'); `orden=asc` lista de menor a mayor. `limit` ∈ [1, 32].","parameters":[{"schema":{"type":"string","description":"Periodo YYYYTQ"},"required":true,"description":"Periodo YYYYTQ","name":"periodo","in":"query"},{"schema":{"type":"string","description":"Slug del indicador"},"required":true,"description":"Slug del indicador","name":"indicador","in":"query"},{"schema":{"type":"string","default":"desc","description":"'desc' (mayor primero) o 'asc' (menor primero)"},"required":false,"description":"'desc' (mayor primero) o 'asc' (menor primero)","name":"orden","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":32,"default":5,"description":"Tamaño del ranking, entre 1 y 32"},"required":false,"description":"Tamaño del ranking, entre 1 y 32","name":"limit","in":"query"}],"responses":{"200":{"description":"Ranking de entidades por valor del indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"},"indicador":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":"string"},"orden":{"type":"string"},"limit":{"type":"integer"},"total_resultados":{"type":"integer"},"ranking":{"type":"array","items":{"type":"object","properties":{"rank":{"type":"integer"},"entidad_clave":{"type":"string"},"entidad_nombre":{"type":"string"},"entidad_abreviatura":{"type":["string","null"],"default":null},"valor":{"type":"number"}},"required":["rank","entidad_clave","entidad_nombre","valor"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["periodo","etapa","indicador","nombre","unidad","orden","limit","total_resultados","ranking","caveats","source"]}}}},"404":{"description":"Sin datos para ese periodo/indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/ocupados/por-sector/snapshot":{"get":{"tags":["enoe"],"operationId":"get_ocupados_por_sector_snapshot_api_v1_enoe_ocupados_por_sector_snapshot_get","summary":"Distribución sectorial de ocupados en un periodo","description":"Composición sectorial de la población ocupada en el periodo dado, a nivel nacional o para una entidad federativa. Cada sector incluye clave SCIAN agregada, nombre, conteo expandido (fac_tri) y % de participación sobre el total ocupado del nivel. Caveats inyectados según el periodo (CPV 2020, dominio 15+, gap 2020T2).","parameters":[{"schema":{"type":"string","description":"Periodo YYYYTQ (ej. 2025T1)"},"required":true,"description":"Periodo YYYYTQ (ej. 2025T1)","name":"periodo","in":"query"},{"schema":{"type":"string","default":"nacional","description":"'nacional' o 'entidad'"},"required":false,"description":"'nacional' o 'entidad'","name":"nivel","in":"query"},{"schema":{"type":"string","description":"Clave AGEE 2 dígitos (ej. '09'); obligatorio si nivel='entidad'"},"required":false,"description":"Clave AGEE 2 dígitos (ej. '09'); obligatorio si nivel='entidad'","name":"geo_clave","in":"query"}],"responses":{"200":{"description":"Composición sectorial nacional o por entidad.","content":{"application/json":{"schema":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"},"nivel":{"type":"string","enum":["nacional","entidad"]},"geo_clave":{"type":["string","null"],"default":null},"geo_nombre":{"type":["string","null"],"default":null},"total_ocupados_nivel":{"type":"integer"},"n_sectores":{"type":"integer"},"distribucion":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":["string","null"],"default":null},"sector_clave":{"type":"string"},"sector_nombre":{"type":"string"},"total_ocupados":{"type":"integer","description":"Personas ocupadas (factor expandido fac_tri)"},"participacion_porcentaje":{"type":"number","description":"% del total ocupados del nivel"},"etapa":{"type":["string","null"],"default":null}},"required":["sector_clave","sector_nombre","total_ocupados","participacion_porcentaje"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"},"source_url":{"type":"string"}},"required":["periodo","etapa","nivel","total_ocupados_nivel","n_sectores","distribucion","caveats","source","source_url"]}}}},"404":{"description":"Sin datos o `geo_clave` inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/ocupados/por-sector/serie":{"get":{"tags":["enoe"],"operationId":"get_ocupados_por_sector_serie_api_v1_enoe_ocupados_por_sector_serie_get","summary":"Serie temporal de ocupación en un sector económico","description":"Trayectoria temporal de ocupados en un sector específico (clave SCIAN agregada '0'..'11'), nacional o para una entidad. Cada punto incluye conteo expandido y % de participación pre-calculado en DB. Caveats inyectados según el rango (cambio de marco 2020T3, dominio 15+, gap 2020T2).","parameters":[{"schema":{"type":"string","description":"Clave SCIAN agregada '0'..'11'"},"required":true,"description":"Clave SCIAN agregada '0'..'11'","name":"sector_clave","in":"query"},{"schema":{"type":"string","default":"nacional","description":"'nacional' o 'entidad'"},"required":false,"description":"'nacional' o 'entidad'","name":"nivel","in":"query"},{"schema":{"type":"string","description":"Obligatorio si nivel='entidad'"},"required":false,"description":"Obligatorio si nivel='entidad'","name":"geo_clave","in":"query"},{"schema":{"type":"string","description":"Periodo inicial YYYYTQ"},"required":false,"description":"Periodo inicial YYYYTQ","name":"desde","in":"query"},{"schema":{"type":"string","description":"Periodo final YYYYTQ"},"required":false,"description":"Periodo final YYYYTQ","name":"hasta","in":"query"}],"responses":{"200":{"description":"Serie temporal de ocupados en un sector.","content":{"application/json":{"schema":{"type":"object","properties":{"sector_clave":{"type":"string"},"sector_nombre":{"type":"string"},"nivel":{"type":"string","enum":["nacional","entidad"]},"geo_clave":{"type":["string","null"],"default":null},"geo_nombre":{"type":["string","null"],"default":null},"cobertura":{"type":"object","properties":{"desde":{"type":["string","null"]},"hasta":{"type":["string","null"]},"n_observaciones":{"type":"integer"}},"required":["desde","hasta","n_observaciones"]},"datos":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":["string","null"],"default":null},"sector_clave":{"type":"string"},"sector_nombre":{"type":"string"},"total_ocupados":{"type":"integer","description":"Personas ocupadas (factor expandido fac_tri)"},"participacion_porcentaje":{"type":"number","description":"% del total ocupados del nivel"},"etapa":{"type":["string","null"],"default":null}},"required":["sector_clave","sector_nombre","total_ocupados","participacion_porcentaje"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["sector_clave","sector_nombre","nivel","cobertura","datos","caveats","source"]}}}},"404":{"description":"`sector_clave` o `geo_clave` no existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/ocupados/por-posicion/snapshot":{"get":{"tags":["enoe"],"operationId":"get_ocupados_por_posicion_snapshot_api_v1_enoe_ocupados_por_posicion_snapshot_get","summary":"Distribución por posición laboral en un periodo","description":"Composición de la población ocupada por posición laboral (asalariados, empleadores, cuenta propia, no remunerados) en el periodo dado, a nivel nacional o por entidad. % participación pre-calculado en DB.","parameters":[{"schema":{"type":"string","description":"Periodo YYYYTQ"},"required":true,"description":"Periodo YYYYTQ","name":"periodo","in":"query"},{"schema":{"type":"string","default":"nacional","description":"'nacional' o 'entidad'"},"required":false,"description":"'nacional' o 'entidad'","name":"nivel","in":"query"},{"schema":{"type":"string","description":"Obligatorio si nivel='entidad'"},"required":false,"description":"Obligatorio si nivel='entidad'","name":"geo_clave","in":"query"}],"responses":{"200":{"description":"Composición por posición laboral.","content":{"application/json":{"schema":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"},"nivel":{"type":"string","enum":["nacional","entidad"]},"geo_clave":{"type":["string","null"],"default":null},"geo_nombre":{"type":["string","null"],"default":null},"total_ocupados_nivel":{"type":"integer"},"n_posiciones":{"type":"integer"},"distribucion":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":["string","null"],"default":null},"pos_clave":{"type":"integer"},"pos_nombre":{"type":"string"},"total_ocupados":{"type":"integer","description":"Personas ocupadas (factor expandido fac_tri)"},"participacion_porcentaje":{"type":"number","description":"% del total ocupados del nivel"},"etapa":{"type":["string","null"],"default":null}},"required":["pos_clave","pos_nombre","total_ocupados","participacion_porcentaje"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"},"source_url":{"type":"string"}},"required":["periodo","etapa","nivel","total_ocupados_nivel","n_posiciones","distribucion","caveats","source","source_url"]}}}},"404":{"description":"Sin datos o `geo_clave` inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/ocupados/por-posicion/serie":{"get":{"tags":["enoe"],"operationId":"get_ocupados_por_posicion_serie_api_v1_enoe_ocupados_por_posicion_serie_get","summary":"Serie temporal de ocupación en una posición laboral","description":"Trayectoria temporal de ocupados en una posición específica (1=subordinados, 2=empleadores, 3=cuenta propia, 4=no remunerados), nacional o por entidad.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":4,"description":"Clave posición 1..4"},"required":true,"description":"Clave posición 1..4","name":"pos_clave","in":"query"},{"schema":{"type":"string","default":"nacional","description":"'nacional' o 'entidad'"},"required":false,"description":"'nacional' o 'entidad'","name":"nivel","in":"query"},{"schema":{"type":"string","description":"Obligatorio si nivel='entidad'"},"required":false,"description":"Obligatorio si nivel='entidad'","name":"geo_clave","in":"query"},{"schema":{"type":"string","description":"Periodo inicial YYYYTQ"},"required":false,"description":"Periodo inicial YYYYTQ","name":"desde","in":"query"},{"schema":{"type":"string","description":"Periodo final YYYYTQ"},"required":false,"description":"Periodo final YYYYTQ","name":"hasta","in":"query"}],"responses":{"200":{"description":"Serie temporal por posición laboral.","content":{"application/json":{"schema":{"type":"object","properties":{"pos_clave":{"type":"integer"},"pos_nombre":{"type":"string"},"nivel":{"type":"string","enum":["nacional","entidad"]},"geo_clave":{"type":["string","null"],"default":null},"geo_nombre":{"type":["string","null"],"default":null},"cobertura":{"type":"object","properties":{"desde":{"type":["string","null"]},"hasta":{"type":["string","null"]},"n_observaciones":{"type":"integer"}},"required":["desde","hasta","n_observaciones"]},"datos":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":["string","null"],"default":null},"pos_clave":{"type":"integer"},"pos_nombre":{"type":"string"},"total_ocupados":{"type":"integer","description":"Personas ocupadas (factor expandido fac_tri)"},"participacion_porcentaje":{"type":"number","description":"% del total ocupados del nivel"},"etapa":{"type":["string","null"],"default":null}},"required":["pos_clave","pos_nombre","total_ocupados","participacion_porcentaje"]}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"}},"required":["pos_clave","pos_nombre","nivel","cobertura","datos","caveats","source"]}}}},"404":{"description":"`pos_clave` o `geo_clave` no existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/microdatos/{tabla}/list":{"get":{"tags":["enoe"],"operationId":"get_microdatos_list_api_v1_enoe_microdatos__tabla__list_get","summary":"Lista de microdatos individuales (paginación por cursor)","description":"Acceso a filas individuales de las 5 tablas de microdatos del ENOE (viv, hog, sdem, coe1, coe2; 101.5 millones de filas). Origen: particiones Parquet por trimestre y entidad ordenadas por la llave primaria, con conteos verificados contra la carga original.\n\n**Filtros obligatorios:**\n- `periodo`: trimestre YYYYTQ (ej. `2025T1`).\n\n**Filtros opcionales:**\n- `entidad_clave`: clave INEGI 2 dígitos `01`..`32` (ej. `09` = CDMX). El alias `entidad` se acepta por compatibilidad pero está deprecated.\n- `sex`, `eda_min`, `eda_max`: SOLO aplicables a `tabla=sdem`. Otras tablas rechazan estos filtros con HTTP 422.\n- `include_extras`: incluir la columna `extras_jsonb` (default `true`). Con `false` en sdem se devuelven solo las columnas núcleo.\n\n**Paginación:** Paginación por cursor: cada respuesta trae `pagination.next_cursor`; para la página siguiente se repite la misma consulta añadiendo `cursor=<ese valor>`. El cursor es la llave de la última fila devuelta, por lo que las páginas son estables y completas aunque la consulta se repita. No hay salto directo a la página N (el legacy lo permitía con `page`; aquí `page` se rechaza con 422).\n- `per_page`: máximo 1000, default 100. `total` es exacto.\n\n**Orden:** dentro del trimestre, entidad federativa primero y después el resto de la llave primaria (ent, cd_a, con, v_sel[, n_hog[, n_ren]]). Con `entidad_clave` el orden coincide con el del legacy; sin él, el legacy ordenaba cd_a antes que ent.\n\n**Tipos:** `ing_x_hrs` (sdem) se devuelve como texto con 5 decimales, como en el legacy (numeric(17,5)).\n\n**Rate limit:** 10/min por IP.\n\n**Caveats:** inyectados según el periodo. Periodos `2020T3-2021T4` tienen subestimación 6-7% en fac_tri (cambio de marco CPV 2020). Periodo `2020T2` no tiene microdatos (gap ETOE).","parameters":[{"schema":{"type":"string","enum":["viv","hog","sdem","coe1","coe2"],"description":"Una de: viv | hog | sdem | coe1 | coe2"},"required":true,"description":"Una de: viv | hog | sdem | coe1 | coe2","name":"tabla","in":"path"},{"schema":{"type":"string","pattern":"^20\\d{2}T[1-4]$","description":"Trimestre YYYYTQ (ej. 2025T1). OBLIGATORIO."},"required":true,"description":"Trimestre YYYYTQ (ej. 2025T1). OBLIGATORIO.","name":"periodo","in":"query"},{"schema":{"type":"string","pattern":"^(0[1-9]|[12][0-9]|3[0-2])$","description":"Clave INEGI '01'..'32' (ej. '09' = CDMX). Opcional; acota la lectura a una sola partición."},"required":false,"description":"Clave INEGI '01'..'32' (ej. '09' = CDMX). Opcional; acota la lectura a una sola partición.","name":"entidad_clave","in":"query"},{"schema":{"type":"string","pattern":"^(0[1-9]|[12][0-9]|3[0-2])$","description":"DEPRECATED: usar `entidad_clave`. Alias retenido por compatibilidad."},"required":false,"description":"DEPRECATED: usar `entidad_clave`. Alias retenido por compatibilidad.","name":"entidad","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2,"description":"Solo sdem. 1=hombre, 2=mujer."},"required":false,"description":"Solo sdem. 1=hombre, 2=mujer.","name":"sex","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":98,"description":"Solo sdem. Edad mínima (años)."},"required":false,"description":"Solo sdem. Edad mínima (años).","name":"eda_min","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":98,"description":"Solo sdem. Edad máxima (años)."},"required":false,"description":"Solo sdem. Edad máxima (años).","name":"eda_max","in":"query"},{"schema":{"type":"boolean","default":true,"description":"Incluir columna extras_jsonb (default true)."},"required":false,"description":"Incluir columna extras_jsonb (default true).","name":"include_extras","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100,"description":"Filas por página, máximo 1000."},"required":false,"description":"Filas por página, máximo 1000.","name":"per_page","in":"query"},{"schema":{"type":"string","description":"`next_cursor` de la respuesta anterior (misma tabla y filtros). Omitir para la primera página."},"required":false,"description":"`next_cursor` de la respuesta anterior (misma tabla y filtros). Omitir para la primera página.","name":"cursor","in":"query"}],"responses":{"200":{"description":"Página de microdatos.","content":{"application/json":{"schema":{"type":"object","properties":{"tabla":{"type":"string"},"filtros":{"type":"object","additionalProperties":{}},"pagination":{"type":"object","properties":{"total":{"type":"integer","description":"Total EXACTO de filas que cumplen los filtros."},"per_page":{"type":"integer"},"returned":{"type":"integer","description":"Filas en esta respuesta."},"has_next":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Cursor para la página siguiente (null si no hay más). Se pasa tal cual en `cursor`."}},"required":["total","per_page","returned","has_next","next_cursor"]},"data":{"type":"array","items":{"type":"object","properties":{"periodo":{"type":"string"},"etapa":{"type":"string"}},"required":["periodo","etapa"],"additionalProperties":{}}},"caveats":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"titulo":{"type":"string"},"descripcion":{"type":"string"},"periodo_aplicable":{"type":"string"},"referencia":{"type":"string"}},"required":["slug","titulo","descripcion","periodo_aplicable","referencia"]}},"source":{"type":"string"},"tiempo_query_ms":{"type":["number","null"],"default":null,"description":"Tiempo de lectura de índice y particiones (sin serialización)."}},"required":["tabla","filtros","pagination","data","caveats","source"]}}}},"422":{"description":"Filtro `sex`/`eda_*` en una tabla distinta de sdem, `tabla` inválida, `cursor` inválido o parámetro `page` (la paginación es por cursor).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{}}}}}},"429":{"description":"Rate limit excedido (10 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/microdatos/{tabla}/count":{"get":{"tags":["enoe"],"operationId":"get_microdatos_count_api_v1_enoe_microdatos__tabla__count_get","summary":"Conteo exacto de microdatos con filtros","description":"Conteo EXACTO de filas de microdatos que coinciden con los filtros. Mismos filtros que `/microdatos/{tabla}/list`. Sin filtros de fila el conteo sale del índice de particiones; con `sex`/`eda_*` se leen solo esas columnas de las particiones del trimestre.\n\n**Uso típico:** saber cuántas filas existen antes de paginar.","parameters":[{"schema":{"type":"string","enum":["viv","hog","sdem","coe1","coe2"],"description":"Una de: viv | hog | sdem | coe1 | coe2"},"required":true,"description":"Una de: viv | hog | sdem | coe1 | coe2","name":"tabla","in":"path"},{"schema":{"type":"string","pattern":"^20\\d{2}T[1-4]$","description":"Trimestre YYYYTQ (ej. 2025T1). OBLIGATORIO."},"required":true,"description":"Trimestre YYYYTQ (ej. 2025T1). OBLIGATORIO.","name":"periodo","in":"query"},{"schema":{"type":"string","pattern":"^(0[1-9]|[12][0-9]|3[0-2])$","description":"Clave INEGI '01'..'32' (ej. '09' = CDMX). Opcional; acota la lectura a una sola partición."},"required":false,"description":"Clave INEGI '01'..'32' (ej. '09' = CDMX). Opcional; acota la lectura a una sola partición.","name":"entidad_clave","in":"query"},{"schema":{"type":"string","pattern":"^(0[1-9]|[12][0-9]|3[0-2])$","description":"DEPRECATED: usar `entidad_clave`. Alias retenido por compatibilidad."},"required":false,"description":"DEPRECATED: usar `entidad_clave`. Alias retenido por compatibilidad.","name":"entidad","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2,"description":"Solo sdem. 1=hombre, 2=mujer."},"required":false,"description":"Solo sdem. 1=hombre, 2=mujer.","name":"sex","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":98,"description":"Solo sdem. Edad mínima (años)."},"required":false,"description":"Solo sdem. Edad mínima (años).","name":"eda_min","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":98,"description":"Solo sdem. Edad máxima (años)."},"required":false,"description":"Solo sdem. Edad máxima (años).","name":"eda_max","in":"query"}],"responses":{"200":{"description":"Conteo exacto + eco de filtros + caveat opcional.","content":{"application/json":{"schema":{"type":"object","properties":{"tabla":{"type":"string"},"filtros":{"type":"object","additionalProperties":{}},"total":{"type":"integer"},"caveat_metodologico":{"type":["string","null"],"default":null},"source":{"type":"string"}},"required":["tabla","filtros","total","source"]}}}},"422":{"description":"Filtro `sex`/`eda_*` enviado a una tabla distinta de sdem."},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/enoe/microdatos/{tabla}/schema":{"get":{"tags":["enoe"],"operationId":"get_microdatos_schema_api_v1_enoe_microdatos__tabla__schema_get","summary":"Schema de una tabla de microdatos","description":"Lista las columnas y tipos (Arrow/Parquet) de una tabla de microdatos, su llave primaria, el total EXACTO de filas y la cobertura temporal, más cómo está almacenada (particiones por trimestre y entidad).\n\n**Uso:** inspeccionar columnas disponibles antes de construir consultas vía `/list`. Las columnas núcleo traen descripción; las demás siguen los identificadores del INEGI (Reconstrucción de variables 2023).","parameters":[{"schema":{"type":"string","enum":["viv","hog","sdem","coe1","coe2"],"description":"Una de: viv | hog | sdem | coe1 | coe2"},"required":true,"description":"Una de: viv | hog | sdem | coe1 | coe2","name":"tabla","in":"path"}],"responses":{"200":{"description":"Metadata estructural de la tabla de microdatos.","content":{"application/json":{"schema":{"type":"object","properties":{"tabla":{"type":"string"},"total_columnas":{"type":"integer"},"total_filas":{"type":"integer"},"cobertura_temporal":{"type":["string","null"]},"columnas":{"type":"array","items":{"type":"object","properties":{"nombre":{"type":"string"},"tipo":{"type":"string"},"nullable":{"type":"boolean"},"descripcion":{"type":["string","null"],"default":null}},"required":["nombre","tipo","nullable"]}},"pk":{"type":"array","items":{"type":"string"}},"indexes":{"type":"array","items":{"type":"string"}},"llave_desde_2025T2":{"type":"array","items":{"type":"string"}},"almacenamiento":{"type":"object","properties":{"formato":{"type":"string"},"particiones":{"type":"integer"},"bytes":{"type":"integer"},"orden":{"type":"string"}},"required":["formato","particiones","bytes","orden"]},"caveat_metodologico":{"type":["string","null"],"default":null}},"required":["tabla","total_columnas","total_filas","cobertura_temporal","columnas","pk","indexes","llave_desde_2025T2","almacenamiento"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/resumen":{"get":{"tags":["inegi"],"operationId":"inegi_resumen","summary":"Cuántos indicadores del INEGI tenemos y hasta cuándo","description":"Resumen verificable del Banco de Indicadores del INEGI en el observatorio: indicadores del catálogo oficial, cuántos tienen observaciones a nivel nacional o estatal, total de observaciones, periodos extremos, fecha de la última actualización publicada por el INEGI y fecha de descarga. Los indicadores 'sin datos' existen en el catálogo del INEGI pero no tienen observaciones a ninguno de los tres niveles que consulta el observatorio (nacional, estatal, municipal).","responses":{"200":{"description":"Resumen del Banco de Indicadores.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"indicadores_catalogo":{"type":"integer"},"indicadores_con_datos":{"type":"integer"},"indicadores_sin_datos":{"type":"integer"},"observaciones":{"type":"integer"},"geografias":{"type":"integer"},"cobertura_geografica":{"type":"string"},"primer_periodo":{"type":["string","null"]},"ultimo_periodo":{"type":["string","null"]},"ultima_actualizacion_inegi":{"type":["string","null"]},"descargado_en":{"type":["string","null"]},"catalogos":{"type":"object","additionalProperties":{"type":"integer"}},"arbol":{"type":"object","properties":{"temas":{"type":"integer"},"indicadores_con_ruta":{"type":"integer"},"indicadores_con_nombre_repetido":{"type":"integer"},"url":{"type":"string"}},"required":["temas","indicadores_con_ruta","indicadores_con_nombre_repetido","url"]}},"required":["fuente","fuente_url","indicadores_catalogo","indicadores_con_datos","indicadores_sin_datos","observaciones","geografias","cobertura_geografica","primer_periodo","ultimo_periodo","ultima_actualizacion_inegi","descargado_en","catalogos","arbol"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/indicadores":{"get":{"tags":["inegi"],"operationId":"inegi_indicadores","summary":"Buscar indicadores del INEGI","description":"Busca en los 31,817 indicadores del catálogo del Banco de Indicadores. `q` busca sin distinguir acentos ni mayúsculas en la descripción del indicador, su ruta temática (`ruta`: tema › subtema › … tal como el INEGI lo muestra en su sitio), su tema y su unidad, y amplía la búsqueda con sinónimos del lenguaje común hacia el vocabulario del INEGI («desempleo» también busca «desocupada», «inflación» busca «precios al consumidor»; los términos usados vienen en `terminos`); el INEGI publica nombres cortos ('Total', 'Mujeres') que miles de indicadores comparten, por lo que la ruta y la posición en el tema (`orden_arbol`) son la forma de ubicarlos. Filtros exactos por `tema`, `frecuencia` y `unidad` (claves de los catálogos), por `tema_arbol` (tema hoja del árbol, ver /api/v1/inegi/arbol) y `con_datos`. Paginado con `limit` (1-500) y `offset`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"tema","in":"query"},{"schema":{"type":"string"},"required":false,"name":"tema_arbol","in":"query"},{"schema":{"type":"string"},"required":false,"name":"frecuencia","in":"query"},{"schema":{"type":"string"},"required":false,"name":"unidad","in":"query"},{"schema":{"type":"boolean"},"required":false,"name":"con_datos","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Indicadores que cumplen los filtros.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"terminos":{"type":"array","items":{"type":"string"}},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"descripcion":{"type":["string","null"]},"tema":{"type":["string","null"]},"tema_descripcion":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"frecuencia_descripcion":{"type":["string","null"]},"unidad":{"type":["string","null"]},"unidad_descripcion":{"type":["string","null"]},"con_datos":{"type":"boolean"},"n_observaciones":{"type":"integer"},"n_geografias":{"type":"integer"},"primer_periodo":{"type":["string","null"]},"ultimo_periodo":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"ruta":{"type":["string","null"]},"tema_arbol":{"type":["string","null"]},"orden_arbol":{"type":["integer","null"]}},"required":["id","descripcion","tema","tema_descripcion","frecuencia","frecuencia_descripcion","unidad","unidad_descripcion","con_datos","n_observaciones","n_geografias","primer_periodo","ultimo_periodo","ultima_actualizacion","ruta","tema_arbol","orden_arbol"]}}},"required":["total","limit","offset","terminos","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/indicadores/{id}":{"get":{"tags":["inegi"],"operationId":"inegi_indicador","summary":"Ficha de un indicador del INEGI","description":"Metadatos completos de un indicador: descripción, tema, frecuencia, unidad, multiplicador, nota metodológica, fuentes, estatus y última actualización publicada por el INEGI, la ruta temática completa del Banco de Indicadores (`ruta_temas`: una lista de temas de la raíz a la hoja por cada tema donde el INEGI lo muestra) con su posición dentro del tema hoja (`orden_arbol`), más las geografías para las que hay observaciones (con su nivel: nacional, entidad, municipio) y el enlace a la serie.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Ficha del indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"descripcion":{"type":["string","null"]},"tema":{"type":["string","null"]},"tema_descripcion":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"frecuencia_descripcion":{"type":["string","null"]},"unidad":{"type":["string","null"]},"unidad_descripcion":{"type":["string","null"]},"con_datos":{"type":"boolean"},"n_observaciones":{"type":"integer"},"n_geografias":{"type":"integer"},"primer_periodo":{"type":["string","null"]},"ultimo_periodo":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"ruta":{"type":["string","null"]},"tema_arbol":{"type":["string","null"]},"orden_arbol":{"type":["integer","null"]},"multiplicador":{"type":["string","null"]},"multiplicador_descripcion":{"type":["string","null"]},"nota":{"type":["string","null"]},"nota_descripcion":{"type":["string","null"]},"fuentes":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["clave","descripcion"]}},"estatus":{"type":["string","null"]},"ultima_actualizacion_texto":{"type":["string","null"]},"descargado_en":{"type":["string","null"]},"geografias":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"string"},"n_observaciones":{"type":"integer"}},"required":["clave","nombre","nivel","n_observaciones"]}},"observaciones_url":{"type":"string"},"ruta_temas":{"type":"array","items":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"}},"required":["tema","nombre","nivel"]}}}},"required":["id","descripcion","tema","tema_descripcion","frecuencia","frecuencia_descripcion","unidad","unidad_descripcion","con_datos","n_observaciones","n_geografias","primer_periodo","ultimo_periodo","ultima_actualizacion","ruta","tema_arbol","orden_arbol","multiplicador","multiplicador_descripcion","nota","nota_descripcion","fuentes","estatus","ultima_actualizacion_texto","descargado_en","geografias","observaciones_url","ruta_temas"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/indicadores/{id}/observaciones":{"get":{"tags":["inegi"],"operationId":"inegi_observaciones","summary":"Serie de un indicador del INEGI","description":"Observaciones de un indicador tal como las publica el INEGI: `valor` es el número y `valor_texto` el decimal original exacto (sin ceros a la derecha). `geografia` filtra por clave (00 nacional, 01-32 entidades, 5 dígitos municipio); sin ella se devuelven todas las geografías. `desde` y `hasta` acotan el periodo por comparación de texto en el formato del INEGI ('2020', '2020/01', '2020/02'...). Orden: geografía y periodo ascendentes. Paginado con `limit` (1-5000) y `offset`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","pattern":"^\\d{2}(\\d{3})?$"},"required":false,"name":"geografia","in":"query"},{"schema":{"type":"string"},"required":false,"name":"desde","in":"query"},{"schema":{"type":"string"},"required":false,"name":"hasta","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000,"default":1000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Observaciones del indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"indicador":{"type":"string"},"descripcion":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"unidad":{"type":["string","null"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"observaciones":{"type":"array","items":{"type":"object","properties":{"geografia":{"type":"string"},"periodo":{"type":"string"},"valor":{"type":["number","null"]},"valor_texto":{"type":["string","null"]},"excepcion":{"type":["string","null"]},"estatus":{"type":["string","null"]},"fuente":{"type":["string","null"]},"nota":{"type":["string","null"]}},"required":["geografia","periodo","valor","valor_texto","excepcion","estatus","fuente","nota"]}}},"required":["indicador","descripcion","frecuencia","unidad","total","limit","offset","observaciones"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/catalogos/{catalogo}":{"get":{"tags":["inegi"],"operationId":"inegi_catalogo","summary":"Catálogo del INEGI (unidades, frecuencias, temas, fuentes, notas, multiplicadores, geografías)","description":"Contenido de un catálogo del Banco de Indicadores tal como lo publica el INEGI (CL_UNIT, CL_FREQ, CL_TOPIC, CL_SOURCE, CL_NOTE, CL_UNIT_MULT). El catálogo 'geografias' contiene 00 nacional, 01-32 entidades y los 2,478 municipios del Marco Geoestadístico 2025 (nivel: nacional, entidad, municipio). Filtro opcional `q` (contiene, sin distinguir mayúsculas).","parameters":[{"schema":{"type":"string","enum":["unidades","frecuencias","temas","fuentes","notas","multiplicadores","geografias"]},"required":true,"name":"catalogo","in":"path"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Catálogo.","content":{"application/json":{"schema":{"type":"object","properties":{"catalogo":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"descripcion":{"type":["string","null"]},"nivel":{"type":"string"}},"required":["clave","descripcion"]}}},"required":["catalogo","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/arbol":{"get":{"tags":["inegi"],"operationId":"inegi_arbol","summary":"Árbol temático del Banco de Indicadores","description":"La jerarquía tema › subtema › … › indicador con la que el INEGI organiza el Banco de Indicadores en su sitio (www.inegi.org.mx/app/indicadores/), recorrida completa el 2026-09-20: 182 temas en hasta cinco niveles. Sin `tema` devuelve los temas raíz; con `tema` devuelve la ruta hasta ese tema, sus subtemas y los indicadores que cuelgan directamente de él en el orden del INEGI (`limit` 1-500 y `offset` paginan los indicadores). El INEGI repite el nombre corto en miles de series (las 2,672 del PIB por actividad económica, por ejemplo): la posición (`orden_arbol`) es lo que las distingue.","parameters":[{"schema":{"type":"string"},"required":false,"name":"tema","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Nodo del árbol.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"ruta":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"}},"required":["tema","nombre","nivel"]}},"tema":{"type":["object","null"],"properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"},"orden":{"type":["integer","null"]},"n_subtemas":{"type":"integer"},"n_indicadores":{"type":"integer"},"url_inegi":{"type":["string","null"]}},"required":["tema","nombre","nivel","orden","n_subtemas","n_indicadores","url_inegi"]},"subtemas":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"},"orden":{"type":["integer","null"]},"n_subtemas":{"type":"integer"},"n_indicadores":{"type":"integer"},"url_inegi":{"type":["string","null"]}},"required":["tema","nombre","nivel","orden","n_subtemas","n_indicadores","url_inegi"]}},"indicadores_total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"indicadores":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"descripcion":{"type":["string","null"]},"tema":{"type":["string","null"]},"tema_descripcion":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"frecuencia_descripcion":{"type":["string","null"]},"unidad":{"type":["string","null"]},"unidad_descripcion":{"type":["string","null"]},"con_datos":{"type":"boolean"},"n_observaciones":{"type":"integer"},"n_geografias":{"type":"integer"},"primer_periodo":{"type":["string","null"]},"ultimo_periodo":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"ruta":{"type":["string","null"]},"tema_arbol":{"type":["string","null"]},"orden_arbol":{"type":["integer","null"]}},"required":["id","descripcion","tema","tema_descripcion","frecuencia","frecuencia_descripcion","unidad","unidad_descripcion","con_datos","n_observaciones","n_geografias","primer_periodo","ultimo_periodo","ultima_actualizacion","ruta","tema_arbol","orden_arbol"]}}},"required":["fuente","ruta","tema","subtemas","indicadores_total","limit","offset","indicadores"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/bie/resumen":{"get":{"tags":["bie"],"operationId":"bie_resumen","summary":"Cuántas series del BIE tenemos y hasta cuándo","description":"Resumen verificable del Banco de Información Económica en el observatorio: series, observaciones, áreas geográficas, temas del árbol, periodos extremos y última actualización publicada por el INEGI. El BIE es el otro banco del INEGI (además del Banco de Indicadores, /api/v1/inegi): inflación (INPC), PIB trimestral, IGAE, balanza comercial, indicadores de coyuntura, cuentas nacionales, manufacturas, sector externo…","responses":{"200":{"description":"Resumen del BIE.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"series":{"type":"integer"},"observaciones":{"type":"integer"},"areas":{"type":"integer"},"temas":{"type":"integer"},"primer_periodo":{"type":["string","null"]},"ultimo_periodo":{"type":["string","null"]},"ultima_actualizacion_inegi":{"type":["string","null"]},"nota":{"type":"string"}},"required":["fuente","series","observaciones","areas","temas","primer_periodo","ultimo_periodo","ultima_actualizacion_inegi","nota"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/bie/series":{"get":{"tags":["bie"],"operationId":"bie_series","summary":"Buscar series del BIE","description":"Busca en las series del Banco de Información Económica. `q` busca sin distinguir acentos ni mayúsculas en el nombre, la ruta temática, la unidad y la fuente, y amplía con sinónimos («inflación» también busca «precios al consumidor»; los términos usados vienen en `terminos`). Filtros: `tema` (tema hoja del árbol, ver /api/v1/bie/arbol), `frecuencia`. Paginado con `limit` (1-500) y `offset`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"tema","in":"query"},{"schema":{"type":"string"},"required":false,"name":"frecuencia","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Series que cumplen los filtros.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"terminos":{"type":"array","items":{"type":"string"}},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"fuente":{"type":["string","null"]},"tema":{"type":["string","null"]},"ruta":{"type":["string","null"]},"periodo_inicial":{"type":["string","null"]},"periodo_final":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"decimales":{"type":["integer","null"]},"n_areas":{"type":"integer"},"n_observaciones":{"type":"integer"}},"required":["id","nombre","unidad","frecuencia","fuente","tema","ruta","periodo_inicial","periodo_final","ultima_actualizacion","decimales","n_areas","n_observaciones"]}}},"required":["total","limit","offset","terminos","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/bie/series/{id}":{"get":{"tags":["bie"],"operationId":"bie_serie","summary":"Ficha de una serie del BIE","description":"Metadatos de una serie (nombre, unidad, frecuencia, fuente, periodos, última actualización del INEGI), su ruta temática completa y las áreas geográficas con observaciones.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"fuente":{"type":["string","null"]},"tema":{"type":["string","null"]},"ruta":{"type":["string","null"]},"periodo_inicial":{"type":["string","null"]},"periodo_final":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"decimales":{"type":["integer","null"]},"n_areas":{"type":"integer"},"n_observaciones":{"type":"integer"},"ruta_temas":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"}},"required":["tema","nombre","nivel"]}},"areas":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"desglose":{"type":"string"},"n_observaciones":{"type":"integer"}},"required":["clave","nombre","desglose","n_observaciones"]}},"observaciones_url":{"type":"string"}},"required":["id","nombre","unidad","frecuencia","fuente","tema","ruta","periodo_inicial","periodo_final","ultima_actualizacion","decimales","n_areas","n_observaciones","ruta_temas","areas","observaciones_url"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/bie/series/{id}/observaciones":{"get":{"tags":["bie"],"operationId":"bie_observaciones","summary":"Serie del BIE (observaciones)","description":"Observaciones de una serie tal como las publica el INEGI: `valor_texto` es el decimal original y `valor` el número; `estatus` es la letra de la cifra cuando el INEGI la publica (D definitiva, P preliminar, R revisada…). `area` filtra por clave (00 nacional, 01-32 entidades; otras áreas en la ficha). `desde`/`hasta` acotan el periodo por comparación de texto en el formato del INEGI ('2020/01', '2020/02'…). Paginado con `limit` (1-5000) y `offset`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"area","in":"query"},{"schema":{"type":"string"},"required":false,"name":"desde","in":"query"},{"schema":{"type":"string"},"required":false,"name":"hasta","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000,"default":1000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Observaciones.","content":{"application/json":{"schema":{"type":"object","properties":{"serie":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"observaciones":{"type":"array","items":{"type":"object","properties":{"area":{"type":"string"},"periodo":{"type":"string"},"valor":{"type":["number","null"]},"valor_texto":{"type":"string"},"estatus":{"type":["string","null"]}},"required":["area","periodo","valor","valor_texto","estatus"]}}},"required":["serie","nombre","unidad","frecuencia","total","limit","offset","observaciones"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/bie/arbol":{"get":{"tags":["bie"],"operationId":"bie_arbol","summary":"Árbol temático del BIE","description":"La jerarquía de temas con la que el INEGI organiza el Banco de Información Económica (14 temas raíz: coyuntura, ocupación, productividad, cuentas nacionales, manufacturas, sector externo…). Sin `tema` devuelve las raíces; con `tema`, la ruta hasta él, sus subtemas y las series que cuelgan directamente de él (`limit`/`offset` paginan las series).","parameters":[{"schema":{"type":"string"},"required":false,"name":"tema","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Nodo.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"ruta":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"}},"required":["tema","nombre","nivel"]}},"tema":{"type":["object","null"],"properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"},"n_subtemas":{"type":"integer"},"n_series":{"type":"integer"}},"required":["tema","nombre","nivel","n_subtemas","n_series"]},"subtemas":{"type":"array","items":{"type":"object","properties":{"tema":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"},"orden":{"type":["integer","null"]},"n_subtemas":{"type":"integer"},"n_series":{"type":"integer"}},"required":["tema","nombre","nivel","orden","n_subtemas","n_series"]}},"series_total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"series":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nombre":{"type":"string"},"unidad":{"type":["string","null"]},"frecuencia":{"type":["string","null"]},"fuente":{"type":["string","null"]},"tema":{"type":["string","null"]},"ruta":{"type":["string","null"]},"periodo_inicial":{"type":["string","null"]},"periodo_final":{"type":["string","null"]},"ultima_actualizacion":{"type":["string","null"]},"decimales":{"type":["integer","null"]},"n_areas":{"type":"integer"},"n_observaciones":{"type":"integer"}},"required":["id","nombre","unidad","frecuencia","fuente","tema","ruta","periodo_inicial","periodo_final","ultima_actualizacion","decimales","n_areas","n_observaciones"]}}},"required":["fuente","ruta","tema","subtemas","series_total","limit","offset","series"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/datos-abiertos/resumen":{"get":{"tags":["inegi-datos-abiertos"],"operationId":"inegi_datos_abiertos_resumen","summary":"Cuánto del INEGI (descarga masiva) tenemos ya","description":"Avance medible contra el inventario de la descarga masiva del INEGI (recorrido programa por programa el 2026-09-20): programas y archivos de microdatos del universo frente a los ingeridos (con filas, tablas y bytes en Parquet), y tabulados del universo frente a los archivados. Todo lo ingerido conserva el archivo original del INEGI (SHA-256) junto al Parquet.","responses":{"200":{"description":"Cobertura.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"inventario":{"type":"string"},"microdatos":{"type":"object","properties":{"programas_universo":{"type":"integer"},"programas_con_algo":{"type":"integer"},"programas_completos":{"type":"integer"},"archivos_universo":{"type":"integer"},"archivos_ingeridos":{"type":"integer"},"tablas":{"type":"integer"},"filas":{"type":"integer"},"gb_parquet":{"type":"number"}},"required":["programas_universo","programas_con_algo","programas_completos","archivos_universo","archivos_ingeridos","tablas","filas","gb_parquet"]},"tabulados":{"type":"object","properties":{"programas_universo":{"type":"integer"},"archivos_universo":{"type":"integer"},"archivos_archivados":{"type":"integer"},"gb":{"type":"number"}},"required":["programas_universo","archivos_universo","archivos_archivados","gb"]},"ultima_ingesta":{"type":["string","null"]}},"required":["fuente","inventario","microdatos","tabulados","ultima_ingesta"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/datos-abiertos/programas":{"get":{"tags":["inegi-datos-abiertos"],"operationId":"inegi_datos_abiertos_programas","summary":"Programas del INEGI: universo e ingerido","description":"Los programas de la descarga masiva del INEGI con cuántos archivos de microdatos y tabulados tiene cada uno en el universo y cuántos ya están en el observatorio. `q` filtra por nombre (contiene, sin distinguir mayúsculas).","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Programas.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"programa":{"type":"string"},"programa_slug":{"type":"string"},"microdatos_universo":{"type":"integer"},"microdatos_ingeridos":{"type":"integer"},"filas_microdatos":{"type":"integer"},"tabulados_universo":{"type":"integer"},"tabulados_ingeridos":{"type":"integer"}},"required":["programa","programa_slug","microdatos_universo","microdatos_ingeridos","filas_microdatos","tabulados_universo","tabulados_ingeridos"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/datos-abiertos/programas/{programa_slug}":{"get":{"tags":["inegi-datos-abiertos"],"operationId":"inegi_datos_abiertos_programa","summary":"Un programa: ediciones, archivos, tablas y esquema","description":"Todo lo ingerido de un programa (por su `programa_slug`): cada tabla Parquet con edición, archivo de origen, filas, columnas y esquema (nombre y tipo por columna), su URL de descarga en el observatorio, la del zip original del INEGI que se conservó y la URL original del INEGI. Filtro opcional `edicion`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"programa_slug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"edicion","in":"query"}],"responses":{"200":{"description":"Programa.","content":{"application/json":{"schema":{"type":"object","properties":{"programa":{"type":"object","properties":{"programa":{"type":"string"},"programa_slug":{"type":"string"},"microdatos_universo":{"type":"integer"},"microdatos_ingeridos":{"type":"integer"},"filas_microdatos":{"type":"integer"},"tabulados_universo":{"type":"integer"},"tabulados_ingeridos":{"type":"integer"}},"required":["programa","programa_slug","microdatos_universo","microdatos_ingeridos","filas_microdatos","tabulados_universo","tabulados_ingeridos"]},"ediciones":{"type":"array","items":{"type":"string"}},"n_tablas":{"type":"integer"},"tablas":{"type":"array","items":{"type":"object","properties":{"edicion":{"type":"string"},"titulo":{"type":["string","null"]},"archivo":{"type":"string"},"tabla":{"type":"string"},"origen":{"type":["string","null"]},"formato":{"type":["string","null"]},"filas":{"type":"integer"},"columnas":{"type":"integer"},"esquema":{"type":"array","items":{"type":"array","prefixItems":[{"type":"string"},{"type":"string"}]}},"bytes_parquet":{"type":"integer"},"parquet_url":{"type":"string"},"fuente_url":{"type":["string","null"]},"url_inegi":{"type":["string","null"]},"sha256_zip":{"type":["string","null"]},"ingerido_en":{"type":["string","null"]}},"required":["edicion","titulo","archivo","tabla","origen","formato","filas","columnas","esquema","bytes_parquet","parquet_url","fuente_url","url_inegi","sha256_zip","ingerido_en"]}},"tabulados":{"type":"integer"}},"required":["programa","ediciones","n_tablas","tablas","tabulados"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/datos-abiertos/tabulados":{"get":{"tags":["inegi-datos-abiertos"],"operationId":"inegi_datos_abiertos_tabulados","summary":"Tabulados archivados (cuadros Excel/HTML/PDF del INEGI)","description":"Índice de los tabulados de la descarga masiva del INEGI archivados íntegros, sin transformar (son cuadros de presentación): programa, edición, título, formato, tamaño, SHA-256 y URL de descarga. Filtros: `programa_slug`, `edicion`, `q` (título). Paginado con `limit` (1-500) y `offset`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"programa_slug","in":"query"},{"schema":{"type":"string"},"required":false,"name":"edicion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Tabulados.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"programa":{"type":"string"},"programa_slug":{"type":"string"},"edicion":{"type":"string"},"titulo":{"type":["string","null"]},"formato":{"type":["string","null"]},"bytes":{"type":["integer","null"]},"sha256":{"type":["string","null"]},"url":{"type":"string"},"url_inegi":{"type":["string","null"]}},"required":["programa","programa_slug","edicion","titulo","formato","bytes","sha256","url","url_inegi"]}}},"required":["total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/datos-abiertos/descarga/*":{"get":{"tags":["inegi-datos-abiertos"],"operationId":"inegi_datos_abiertos_descarga","summary":"Descargar un Parquet, un zip original o un tabulado del almacén","description":"Entrega el archivo tal como está guardado en el almacén del observatorio (R2): Parquet de microdatos, zip original del INEGI o tabulado. La clave es la ruta que aparece en `parquet_url`, `fuente_url` o `url` de los otros endpoints (prefijos `inegi/microdatos/`, `inegi/fuentes/`, `inegi/tabulados/`, `enoe/microdatos/`, `censo2020/`). Respuesta binaria con `Content-Length` y ETag.","parameters":[{"schema":{"type":"string"},"required":true,"name":"clave","in":"path"}],"responses":{"200":{"description":"El archivo."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/resumen":{"get":{"tags":["denue"],"operationId":"denue_resumen","summary":"Cuántas unidades económicas del DENUE tenemos","description":"Resumen verificable del DENUE cargado: edición del INEGI, total de unidades económicas, estados, municipios y actividades SCIAN distintas, y distribución por estrato de personal ocupado. Es el directorio completo de descarga masiva del INEGI, sin recortes.","responses":{"200":{"description":"Resumen del DENUE.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"edicion":{"type":["string","null"]},"fecha_diccionario":{"type":["string","null"]},"unidades_economicas":{"type":"integer"},"estados":{"type":"integer"},"municipios":{"type":"integer"},"actividades":{"type":"integer"},"por_estrato":{"type":"array","items":{"type":"object","properties":{"per_ocu":{"type":["string","null"]},"n":{"type":"integer"}},"required":["per_ocu","n"]}},"descargado_en":{"type":["string","null"]}},"required":["fuente","fuente_url","edicion","fecha_diccionario","unidades_economicas","estados","municipios","actividades","por_estrato","descargado_en"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/unidades":{"get":{"tags":["denue"],"operationId":"denue_unidades","summary":"Buscar unidades económicas","description":"Busca en el DENUE completo. `q` busca (contiene, sin distinguir mayúsculas) en el nombre del establecimiento y en la razón social. Filtros exactos: `cve_ent` (2 dígitos), `cve_mun` (3 dígitos, requiere cve_ent), `cod_postal` (5 dígitos), `per_ocu` (estrato textual del INEGI, p. ej. '0 a 5 personas'). `codigo_act` acepta el código SCIAN completo (6 dígitos) o un prefijo (2 a 5 dígitos: sector, subsector, rama, subrama). Paginado con `limit` (1-500) y `offset`; orden por id.","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"cve_ent","in":"query"},{"schema":{"type":"string","pattern":"^\\d{3}$"},"required":false,"name":"cve_mun","in":"query"},{"schema":{"type":"string","pattern":"^\\d{5}$"},"required":false,"name":"cod_postal","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2,6}$"},"required":false,"name":"codigo_act","in":"query"},{"schema":{"type":"string"},"required":false,"name":"per_ocu","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Unidades que cumplen los filtros.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"clee":{"type":["string","null"]},"nom_estab":{"type":["string","null"]},"raz_social":{"type":["string","null"]},"codigo_act":{"type":["string","null"]},"nombre_act":{"type":["string","null"]},"per_ocu":{"type":["string","null"]},"tipo_vial":{"type":["string","null"]},"nom_vial":{"type":["string","null"]},"tipo_v_e_1":{"type":["string","null"]},"nom_v_e_1":{"type":["string","null"]},"tipo_v_e_2":{"type":["string","null"]},"nom_v_e_2":{"type":["string","null"]},"tipo_v_e_3":{"type":["string","null"]},"nom_v_e_3":{"type":["string","null"]},"numero_ext":{"type":["string","null"]},"letra_ext":{"type":["string","null"]},"edificio":{"type":["string","null"]},"edificio_e":{"type":["string","null"]},"numero_int":{"type":["string","null"]},"letra_int":{"type":["string","null"]},"tipo_asent":{"type":["string","null"]},"nomb_asent":{"type":["string","null"]},"tipo_cencom":{"type":["string","null"]},"nom_cencom":{"type":["string","null"]},"num_local":{"type":["string","null"]},"cod_postal":{"type":["string","null"]},"cve_ent":{"type":["string","null"]},"entidad":{"type":["string","null"]},"cve_mun":{"type":["string","null"]},"municipio":{"type":["string","null"]},"cve_loc":{"type":["string","null"]},"localidad":{"type":["string","null"]},"ageb":{"type":["string","null"]},"manzana":{"type":["string","null"]},"telefono":{"type":["string","null"]},"correoelec":{"type":["string","null"]},"www":{"type":["string","null"]},"tipo_unieco":{"type":["string","null"]},"latitud":{"type":["number","null"]},"longitud":{"type":["number","null"]},"fecha_alta":{"type":["string","null"]}},"required":["id","clee","nom_estab","raz_social","codigo_act","nombre_act","per_ocu","tipo_vial","nom_vial","tipo_v_e_1","nom_v_e_1","tipo_v_e_2","nom_v_e_2","tipo_v_e_3","nom_v_e_3","numero_ext","letra_ext","edificio","edificio_e","numero_int","letra_int","tipo_asent","nomb_asent","tipo_cencom","nom_cencom","num_local","cod_postal","cve_ent","entidad","cve_mun","municipio","cve_loc","localidad","ageb","manzana","telefono","correoelec","www","tipo_unieco","latitud","longitud","fecha_alta"]}}},"required":["total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/unidades/cerca":{"get":{"tags":["denue"],"operationId":"denue_cerca","summary":"Unidades económicas cerca de un punto","description":"Unidades económicas a menos de `radio` metros (1-5000, por defecto 500) de una coordenada (`latitud`, `longitud`), ordenadas por distancia (fórmula de haversine sobre las coordenadas del INEGI). Filtro opcional por `codigo_act` (código o prefijo SCIAN) y `q` (nombre o razón social). Devuelve hasta `limit` (1-500) resultados y el total dentro del radio.","parameters":[{"schema":{"type":"number","minimum":14,"maximum":33},"required":true,"name":"latitud","in":"query"},{"schema":{"type":"number","minimum":-119,"maximum":-86},"required":true,"name":"longitud","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000,"default":500},"required":false,"name":"radio","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2,6}$"},"required":false,"name":"codigo_act","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Unidades dentro del radio, por distancia.","content":{"application/json":{"schema":{"type":"object","properties":{"latitud":{"type":"number"},"longitud":{"type":"number"},"radio_m":{"type":"integer"},"total":{"type":"integer"},"limit":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"clee":{"type":["string","null"]},"nom_estab":{"type":["string","null"]},"raz_social":{"type":["string","null"]},"codigo_act":{"type":["string","null"]},"nombre_act":{"type":["string","null"]},"per_ocu":{"type":["string","null"]},"tipo_vial":{"type":["string","null"]},"nom_vial":{"type":["string","null"]},"tipo_v_e_1":{"type":["string","null"]},"nom_v_e_1":{"type":["string","null"]},"tipo_v_e_2":{"type":["string","null"]},"nom_v_e_2":{"type":["string","null"]},"tipo_v_e_3":{"type":["string","null"]},"nom_v_e_3":{"type":["string","null"]},"numero_ext":{"type":["string","null"]},"letra_ext":{"type":["string","null"]},"edificio":{"type":["string","null"]},"edificio_e":{"type":["string","null"]},"numero_int":{"type":["string","null"]},"letra_int":{"type":["string","null"]},"tipo_asent":{"type":["string","null"]},"nomb_asent":{"type":["string","null"]},"tipo_cencom":{"type":["string","null"]},"nom_cencom":{"type":["string","null"]},"num_local":{"type":["string","null"]},"cod_postal":{"type":["string","null"]},"cve_ent":{"type":["string","null"]},"entidad":{"type":["string","null"]},"cve_mun":{"type":["string","null"]},"municipio":{"type":["string","null"]},"cve_loc":{"type":["string","null"]},"localidad":{"type":["string","null"]},"ageb":{"type":["string","null"]},"manzana":{"type":["string","null"]},"telefono":{"type":["string","null"]},"correoelec":{"type":["string","null"]},"www":{"type":["string","null"]},"tipo_unieco":{"type":["string","null"]},"latitud":{"type":["number","null"]},"longitud":{"type":["number","null"]},"fecha_alta":{"type":["string","null"]},"distancia_m":{"type":"number"}},"required":["id","clee","nom_estab","raz_social","codigo_act","nombre_act","per_ocu","tipo_vial","nom_vial","tipo_v_e_1","nom_v_e_1","tipo_v_e_2","nom_v_e_2","tipo_v_e_3","nom_v_e_3","numero_ext","letra_ext","edificio","edificio_e","numero_int","letra_int","tipo_asent","nomb_asent","tipo_cencom","nom_cencom","num_local","cod_postal","cve_ent","entidad","cve_mun","municipio","cve_loc","localidad","ageb","manzana","telefono","correoelec","www","tipo_unieco","latitud","longitud","fecha_alta","distancia_m"]}}},"required":["latitud","longitud","radio_m","total","limit","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/unidades/{id}":{"get":{"tags":["denue"],"operationId":"denue_unidad","summary":"Ficha de una unidad económica","description":"Los 42 campos del DENUE de una unidad económica, tal como los publica el INEGI, por su `id` numérico.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Unidad económica.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"clee":{"type":["string","null"]},"nom_estab":{"type":["string","null"]},"raz_social":{"type":["string","null"]},"codigo_act":{"type":["string","null"]},"nombre_act":{"type":["string","null"]},"per_ocu":{"type":["string","null"]},"tipo_vial":{"type":["string","null"]},"nom_vial":{"type":["string","null"]},"tipo_v_e_1":{"type":["string","null"]},"nom_v_e_1":{"type":["string","null"]},"tipo_v_e_2":{"type":["string","null"]},"nom_v_e_2":{"type":["string","null"]},"tipo_v_e_3":{"type":["string","null"]},"nom_v_e_3":{"type":["string","null"]},"numero_ext":{"type":["string","null"]},"letra_ext":{"type":["string","null"]},"edificio":{"type":["string","null"]},"edificio_e":{"type":["string","null"]},"numero_int":{"type":["string","null"]},"letra_int":{"type":["string","null"]},"tipo_asent":{"type":["string","null"]},"nomb_asent":{"type":["string","null"]},"tipo_cencom":{"type":["string","null"]},"nom_cencom":{"type":["string","null"]},"num_local":{"type":["string","null"]},"cod_postal":{"type":["string","null"]},"cve_ent":{"type":["string","null"]},"entidad":{"type":["string","null"]},"cve_mun":{"type":["string","null"]},"municipio":{"type":["string","null"]},"cve_loc":{"type":["string","null"]},"localidad":{"type":["string","null"]},"ageb":{"type":["string","null"]},"manzana":{"type":["string","null"]},"telefono":{"type":["string","null"]},"correoelec":{"type":["string","null"]},"www":{"type":["string","null"]},"tipo_unieco":{"type":["string","null"]},"latitud":{"type":["number","null"]},"longitud":{"type":["number","null"]},"fecha_alta":{"type":["string","null"]}},"required":["id","clee","nom_estab","raz_social","codigo_act","nombre_act","per_ocu","tipo_vial","nom_vial","tipo_v_e_1","nom_v_e_1","tipo_v_e_2","nom_v_e_2","tipo_v_e_3","nom_v_e_3","numero_ext","letra_ext","edificio","edificio_e","numero_int","letra_int","tipo_asent","nomb_asent","tipo_cencom","nom_cencom","num_local","cod_postal","cve_ent","entidad","cve_mun","municipio","cve_loc","localidad","ageb","manzana","telefono","correoelec","www","tipo_unieco","latitud","longitud","fecha_alta"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/actividades":{"get":{"tags":["denue"],"operationId":"denue_actividades","summary":"Actividades económicas (SCIAN 2018) presentes en el DENUE","description":"Catálogo de códigos de actividad SCIAN 2018 derivado del propio directorio, con el número de unidades económicas de cada uno. `q` filtra por nombre (contiene, sin distinguir mayúsculas) y `prefijo` por los primeros dígitos del código (sector, subsector, rama, subrama).","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","pattern":"^\\d{1,6}$"},"required":false,"name":"prefijo","in":"query"}],"responses":{"200":{"description":"Actividades.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"codigo_act":{"type":"string"},"nombre_act":{"type":["string","null"]},"n_unidades":{"type":"integer"}},"required":["codigo_act","nombre_act","n_unidades"]}}},"required":["n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores":{"get":{"tags":["clasificadores"],"operationId":"clasificadores_lista","summary":"Qué catálogos y clasificadores del INEGI tenemos y cómo se verificaron","description":"SCIAN 2023, 2018 y 2013 (con índice de productos), SINCO 2019 y 2011, Clasificación Mexicana de Ocupaciones (histórica) y el Catálogo Único de Claves de Áreas Geoestadísticas (entidades, municipios, localidades). Para cada uno: origen exacto, versión o corte que declara el INEGI, filas cargadas y los conteos por nivel obtenidos contra los publicados por el INEGI.","responses":{"200":{"description":"Catálogos.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"catalogo":{"type":"string"},"titulo":{"type":"string"},"version":{"type":"string"},"fuente_url":{"type":"string"},"corte":{"type":["string","null"]},"filas":{"type":"integer"},"verificacion":{"type":"array","items":{"type":"object","properties":{"nivel":{"type":"string"},"obtenido":{"type":"integer"},"publicado":{"type":["integer","null"]},"estado":{"type":"string"}},"required":["nivel","obtenido","publicado","estado"]}}},"required":["catalogo","titulo","version","fuente_url","corte","filas","verificacion"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/scian":{"get":{"tags":["clasificadores"],"operationId":"clasificador_scian","summary":"SCIAN: sectores, subsectores, ramas, subramas y clases","description":"Sistema de Clasificación Industrial de América del Norte, tal como lo publica el INEGI (archivo de estructura y productos del visor SCIAN). `version` 2023 (por omisión), 2018 o 2013; `nivel` sector, subsector, rama, subrama o clase; `codigo_padre` para descender un nivel; `q` busca en título y descripción. Cada categoría trae descripción, «incluye», «excluye» y la marca de comparabilidad con Canadá y Estados Unidos.","parameters":[{"schema":{"type":"string","enum":["2013","2018","2023"]},"required":false,"name":"version","in":"query"},{"schema":{"type":"string","enum":["sector","subsector","rama","subrama","clase"]},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"codigo_padre","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2000,"default":200},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Categorías.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}}},"required":["clasificador","version","total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/scian/{codigo}":{"get":{"tags":["clasificadores"],"operationId":"clasificador_scian_codigo","summary":"Una categoría del SCIAN con sus ancestros, hijos y productos","description":"Ficha completa de un código: la categoría, la cadena de ancestros hasta el nivel superior, los hijos directos y, en el SCIAN, el índice de productos de la clase; en la CMO, las ocupaciones individuales del grupo unitario.","parameters":[{"schema":{"type":"string"},"required":true,"name":"codigo","in":"path"},{"schema":{"type":"string","enum":["2013","2018","2023"]},"required":false,"name":"version","in":"query"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"categoria":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}},"ancestros":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"hijos":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"productos":{"type":"array","items":{"type":"string"}},"ocupaciones":{"type":"array","items":{"type":"string"}}},"required":["clasificador","version","categoria","ancestros","hijos"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/sinco":{"get":{"tags":["clasificadores"],"operationId":"clasificador_sinco","summary":"SINCO: divisiones, grupos principales, subgrupos y grupos unitarios","description":"Sistema Nacional de Clasificación de Ocupaciones. `version` 2019 (por omisión; edición 2020 con la fe de erratas de 2025) o 2011; `nivel` division, grupo_principal, subgrupo o grupo_unitario. La versión 2019 trae descripción y ocupaciones de ejemplo (extraídas del documento oficial, que el INEGI solo publica en PDF); 2011 solo códigos y títulos.","parameters":[{"schema":{"type":"string","enum":["2011","2019"]},"required":false,"name":"version","in":"query"},{"schema":{"type":"string","enum":["division","grupo_principal","subgrupo","grupo_unitario"]},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"codigo_padre","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2000,"default":200},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Categorías.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}}},"required":["clasificador","version","total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/sinco/{codigo}":{"get":{"tags":["clasificadores"],"operationId":"clasificador_sinco_codigo","summary":"Una categoría del SINCO con sus ancestros e hijos","description":"Ficha completa de un código: la categoría, la cadena de ancestros hasta el nivel superior, los hijos directos y, en el SCIAN, el índice de productos de la clase; en la CMO, las ocupaciones individuales del grupo unitario.","parameters":[{"schema":{"type":"string"},"required":true,"name":"codigo","in":"path"},{"schema":{"type":"string","enum":["2011","2019"]},"required":false,"name":"version","in":"query"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"categoria":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}},"ancestros":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"hijos":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"productos":{"type":"array","items":{"type":"string"}},"ocupaciones":{"type":"array","items":{"type":"string"}}},"required":["clasificador","version","categoria","ancestros","hijos"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/cmo":{"get":{"tags":["clasificadores"],"operationId":"clasificador_cmo","summary":"CMO (histórica): grupos principales, subgrupos y grupos unitarios","description":"Clasificación Mexicana de Ocupaciones (versión histórica, la que usó la ENOE hasta 2012), extraída de los volúmenes I y II que el INEGI publica en PDF. `nivel` grupo_principal, subgrupo o grupo_unitario.","parameters":[{"schema":{"type":"string","enum":["grupo_principal","subgrupo","grupo_unitario"]},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"codigo_padre","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2000,"default":200},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Categorías.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}}},"required":["clasificador","version","total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clasificadores/cmo/{codigo}":{"get":{"tags":["clasificadores"],"operationId":"clasificador_cmo_codigo","summary":"Una categoría de la CMO con sus ancestros, hijos y ocupaciones","description":"Ficha completa de un código: la categoría, la cadena de ancestros hasta el nivel superior, los hijos directos y, en el SCIAN, el índice de productos de la clase; en la CMO, las ocupaciones individuales del grupo unitario.","parameters":[{"schema":{"type":"string"},"required":true,"name":"codigo","in":"path"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","properties":{"clasificador":{"type":"string"},"version":{"type":["string","null"]},"categoria":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}},"ancestros":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"hijos":{"type":"array","items":{"type":"object","properties":{"version":{"type":["string","null"]},"nivel":{"type":"string"},"codigo":{"type":"string"},"codigo_padre":{"type":["string","null"]},"titulo":{"type":"string"},"descripcion":{"type":["string","null"]}},"required":["version","nivel","codigo","codigo_padre","titulo","descripcion"],"additionalProperties":{}}},"productos":{"type":"array","items":{"type":"string"}},"ocupaciones":{"type":"array","items":{"type":"string"}}},"required":["clasificador","version","categoria","ancestros","hijos"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/geo/entidades":{"get":{"tags":["clasificadores"],"operationId":"geo_entidades","summary":"Las 32 entidades federativas (Catálogo Único de Claves de Áreas Geoestadísticas)","description":"Clave, nombre oficial y abreviatura del INEGI, con la población y viviendas habitadas del Censo 2020 que el catálogo trae asociadas.","responses":{"200":{"description":"Entidades.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"cve_ent":{"type":"string"},"nom_ent":{"type":"string"},"nom_abr":{"type":["string","null"]},"pob_total":{"type":["integer","null"]},"pob_masculina":{"type":["integer","null"]},"pob_femenina":{"type":["integer","null"]},"viviendas_habitadas":{"type":["integer","null"]},"fecha_corte":{"type":["string","null"]}},"required":["cve_ent","nom_ent","nom_abr","pob_total","pob_masculina","pob_femenina","viviendas_habitadas","fecha_corte"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/geo/municipios":{"get":{"tags":["clasificadores"],"operationId":"geo_municipios","summary":"Los 2,478 municipios y demarcaciones (corte 2026/06)","description":"Catálogo Único de Claves de Áreas Geoestadísticas Municipales del INEGI: clave, nombre, cabecera municipal y población del Censo 2020. Filtros `cve_ent` (2 dígitos) y `q` (nombre contiene).","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"cve_ent","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Municipios.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"cve_ent":{"type":"string"},"cve_mun":{"type":"string"},"cvegeo":{"type":"string"},"nom_ent":{"type":"string"},"nom_mun":{"type":"string"},"cve_cab":{"type":["string","null"]},"nom_cab":{"type":["string","null"]},"pob_total":{"type":["integer","null"]},"viviendas_habitadas":{"type":["integer","null"]},"fecha_corte":{"type":["string","null"]}},"required":["cve_ent","cve_mun","cvegeo","nom_ent","nom_mun","cve_cab","nom_cab","pob_total","viviendas_habitadas","fecha_corte"],"additionalProperties":{}}}},"required":["n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/geo/localidades":{"get":{"tags":["clasificadores"],"operationId":"geo_localidades","summary":"Las 296,633 localidades vigentes (corte 2026/08) con coordenadas y población","description":"Catálogo Único de Claves de Áreas Geoestadísticas de Localidades: clave, nombre, ámbito (U urbana, R rural), latitud, longitud, altitud, carta topográfica y población y viviendas del Censo 2020 (vacío donde el INEGI no la publica). Filtros: `cve_ent`, `cve_mun` (requiere cve_ent), `ambito` (U o R), `q` (nombre contiene). Paginado con `limit` (1-1000) y `offset`.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"cve_ent","in":"query"},{"schema":{"type":"string","pattern":"^\\d{3}$"},"required":false,"name":"cve_mun","in":"query"},{"schema":{"type":"string","enum":["U","R"]},"required":false,"name":"ambito","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Localidades.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"cve_ent":{"type":"string"},"cve_mun":{"type":"string"},"cve_loc":{"type":"string"},"cvegeo":{"type":"string"},"nom_ent":{"type":"string"},"nom_mun":{"type":"string"},"nom_loc":{"type":"string"},"ambito":{"type":["string","null"]},"lat":{"type":["number","null"]},"lon":{"type":["number","null"]},"altitud":{"type":["integer","null"]},"pob_total":{"type":["integer","null"]},"fecha_corte":{"type":["string","null"]}},"required":["cve_ent","cve_mun","cve_loc","cvegeo","nom_ent","nom_mun","nom_loc","ambito","lat","lon","altitud","pob_total","fecha_corte"],"additionalProperties":{}}}},"required":["total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/geo/localidades/{cvegeo}":{"get":{"tags":["clasificadores"],"operationId":"geo_localidad","summary":"Una localidad por su clave geoestadística (9 dígitos)","parameters":[{"schema":{"type":"string","pattern":"^\\d{9}$"},"required":true,"name":"cvegeo","in":"path"}],"responses":{"200":{"description":"Localidad.","content":{"application/json":{"schema":{"type":"object","properties":{"cve_ent":{"type":"string"},"cve_mun":{"type":"string"},"cve_loc":{"type":"string"},"cvegeo":{"type":"string"},"nom_ent":{"type":"string"},"nom_mun":{"type":"string"},"nom_loc":{"type":"string"},"ambito":{"type":["string","null"]},"lat":{"type":["number","null"]},"lon":{"type":["number","null"]},"altitud":{"type":["integer","null"]},"pob_total":{"type":["integer","null"]},"fecha_corte":{"type":["string","null"]}},"required":["cve_ent","cve_mun","cve_loc","cvegeo","nom_ent","nom_mun","nom_loc","ambito","lat","lon","altitud","pob_total","fecha_corte"],"additionalProperties":{}}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/tabulados":{"get":{"tags":["inegi"],"operationId":"inegi_tabulados_familias","summary":"Tabulados del INEGI explorables: familias de cuadros (censos de población, cuentas por sectores institucionales)","description":"Cada familia agrupa los cuadros publicados en Excel por el INEGI para un programa y edición, leídos tal cual (cada celda numérica con las categorías de su fila y el encabezado de su columna). Un cubo por familia en /api/v1/cubos (tabulados-*). Control de lectura: el número de celdas numéricas leídas de cada hoja es igual al de la hoja; el archivo original está en /archivo con su SHA-256.","responses":{"200":{"description":"Familias.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"familia":{"type":"string"},"nombre":{"type":"string"},"programa":{"type":"string"},"edicion":{"type":"string"},"fuente_url":{"type":"string"},"archivos":{"type":"integer"},"cuadros":{"type":"integer"},"celdas":{"type":"integer"},"corte":{"type":["string","null"]},"cuadros_url":{"type":"string"},"cubo":{"type":"string"}},"required":["familia","nombre","programa","edicion","fuente_url","archivos","cuadros","celdas","corte","cuadros_url","cubo"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/tabulados/{familia}":{"get":{"tags":["inegi"],"operationId":"inegi_tabulados_cuadros","summary":"Cuadros de una familia de tabulados, con su título, dimensiones de fila y encabezados de columna","parameters":[{"schema":{"type":"string"},"required":true,"name":"familia","in":"path"}],"responses":{"200":{"description":"Cuadros.","content":{"application/json":{"schema":{"type":"object","properties":{"familia":{"type":"string"},"nombre":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"cuadro":{"type":"string"},"archivo":{"type":"string"},"hoja":{"type":"string"},"titulo":{"type":"string"},"dimensiones":{"type":"array","items":{"type":"string"}},"columnas":{"type":"array","items":{"type":"string"}},"celdas":{"type":"integer"},"sha256":{"type":"string"},"archivo_url":{"type":["string","null"]}},"required":["cuadro","archivo","hoja","titulo","dimensiones","columnas","celdas","sha256","archivo_url"]}}},"required":["familia","nombre","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/tabulados/{familia}/{cuadro}":{"get":{"tags":["inegi"],"operationId":"inegi_tabulados_cuadro","summary":"Un cuadro: ficha y sus celdas en formato largo (filtrables por dimensión y columna), en el orden del cuadro publicado","description":"Filtros: `d1`…`d5` (valor exacto de cada dimensión de fila, en el orden de `dimensiones`), `columna` (encabezado exacto), `limit` (≤ 5000), `offset`. Cada celda trae `valor` (número) o `texto` (símbolo publicado en vez de número) y `orden` (posición en el cuadro).","parameters":[{"schema":{"type":"string"},"required":true,"name":"familia","in":"path"},{"schema":{"type":"string"},"required":true,"name":"cuadro","in":"path"},{"schema":{"type":"string"},"required":false,"name":"d1","in":"query"},{"schema":{"type":"string"},"required":false,"name":"d2","in":"query"},{"schema":{"type":"string"},"required":false,"name":"d3","in":"query"},{"schema":{"type":"string"},"required":false,"name":"d4","in":"query"},{"schema":{"type":"string"},"required":false,"name":"d5","in":"query"},{"schema":{"type":"string"},"required":false,"name":"columna","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000,"default":500},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Cuadro.","content":{"application/json":{"schema":{"type":"object","properties":{"familia":{"type":"string"},"cuadro":{"type":"object","properties":{"cuadro":{"type":"string"},"archivo":{"type":"string"},"hoja":{"type":"string"},"titulo":{"type":"string"},"dimensiones":{"type":"array","items":{"type":"string"}},"columnas":{"type":"array","items":{"type":"string"}},"celdas":{"type":"integer"},"sha256":{"type":"string"},"archivo_url":{"type":["string","null"]}},"required":["cuadro","archivo","hoja","titulo","dimensiones","columnas","celdas","sha256","archivo_url"]},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"d1":{"type":"string"},"d2":{"type":"string"},"d3":{"type":"string"},"d4":{"type":"string"},"d5":{"type":"string"},"columna":{"type":"string"},"valor":{"type":["number","null"]},"texto":{"type":["string","null"]},"orden":{"type":"integer"}},"required":["d1","d2","d3","d4","d5","columna","valor","texto","orden"]}}},"required":["familia","cuadro","total","limit","offset","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/tabulados/{familia}/{cuadro}/archivo":{"get":{"tags":["inegi"],"operationId":"inegi_tabulados_archivo","summary":"Descargar el archivo Excel original del cuadro (tal como lo publicó el INEGI)","parameters":[{"schema":{"type":"string"},"required":true,"name":"familia","in":"path"},{"schema":{"type":"string"},"required":true,"name":"cuadro","in":"path"}],"responses":{"200":{"description":"Excel."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/saic":{"get":{"tags":["inegi"],"operationId":"inegi_saic_resumen","summary":"Censos Económicos 2004-2024 por municipio, actividad y estrato — qué hay y cómo se verificó","description":"Años censales cargados (2003 = Censos Económicos 2004 … 2023 = Censos Económicos 2024) con filas (nacional + entidades, y municipales), valores, fuente (datos abiertos del INEGI: 33 archivos por censo, el mismo cuadro que sirve el SAIC), si el año está completo, la descarga en Parquet (todas las filas y las 98 variables), y los totales nacionales de unidades económicas y personal ocupado por año, que se cotejan contra el Banco de Indicadores del INEGI (indicador 5300000001). Las 98 variables están en /api/v1/inegi/saic/variables y el árbol de actividad en /api/v1/inegi/saic/actividades.","responses":{"200":{"description":"Resumen.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"anios":{"type":"array","items":{"type":"object","properties":{"anio":{"type":"string"},"censo":{"type":"string"},"filas":{"type":"integer"},"filas_municipales":{"type":["integer","null"]},"valores":{"type":"integer"},"fuente":{"type":"string"},"archivos":{"type":["integer","null"]},"completo":{"type":"boolean"},"parquet_url":{"type":["string","null"]},"unidades_economicas":{"type":["number","null"]},"personal_ocupado":{"type":["number","null"]}},"required":["anio","censo","filas","filas_municipales","valores","fuente","archivos","completo","parquet_url","unidades_economicas","personal_ocupado"]}},"variables":{"type":"integer"},"variables_municipales":{"type":"array","items":{"type":"string"}},"actividades":{"type":"integer"},"estratos":{"type":"array","items":{"type":"object","properties":{"cod":{"type":"integer"},"nombre":{"type":"string"}},"required":["cod","nombre"]}}},"required":["fuente","fuente_url","anios","variables","variables_municipales","actividades","estratos"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/saic/variables":{"get":{"tags":["inegi"],"operationId":"inegi_saic_variables","summary":"Las 98 variables censales del SAIC con su definición","responses":{"200":{"description":"Variables.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"grupo":{"type":"string"},"grupo_nombre":{"type":"string"},"definicion":{"type":["string","null"]}},"required":["clave","nombre","grupo","grupo_nombre","definicion"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/saic/actividades":{"get":{"tags":["inegi"],"operationId":"inegi_saic_actividades","summary":"Árbol de actividad económica del SAIC (sector › subsector › rama › subrama › clase)","parameters":[{"schema":{"type":"integer","minimum":0,"maximum":5},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"padre","in":"query"}],"responses":{"200":{"description":"Actividades.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"nivel":{"type":"integer"},"padre":{"type":["string","null"]}},"required":["clave","nombre","nivel","padre"]}}},"required":["n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/saic/datos":{"get":{"tags":["inegi"],"operationId":"inegi_saic_datos","summary":"Datos del SAIC: filas por año, geografía, actividad y estrato con las variables pedidas","description":"Filtros: `anio` (año censal: 2003, 2008, 2013, 2018, 2023; obligatorio), `nivel_act` (0 total, 1 sector … 5 clase; obligatorio), `cve_ent` (2 dígitos; '00' nacional; sin él, las 32 entidades), `cve_mun` (3 dígitos, requiere cve_ent; sin él, la fila de la entidad; 'todos' = todos los municipios de la entidad), `clave_act` (clave del nivel pedido o prefijo), `estrato` (0 suma de estratos, 1 = 0 a 10, 2 = 11 a 50, 3 = 51 a 250, 4 = 251 y más, 99 agrupados por confidencialidad; por omisión 0), `variables` (claves separadas por coma; por omisión UE, H001A, J000A, A111A, A131A, Q000A; para filas municipales solo las nueve principales UE, H001A, J000A, A111A, A131A, A221A, Q000A, M000A, K000A: las 98 municipales están en el Parquet de /descarga/{año}), `limit` (≤ 2000), `offset`.","parameters":[{"schema":{"type":"string","pattern":"^\\d{4}$"},"required":true,"name":"anio","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":5},"required":true,"name":"nivel_act","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"cve_ent","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cve_mun","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clave_act","in":"query"},{"schema":{"type":"integer"},"required":false,"name":"estrato","in":"query"},{"schema":{"type":"string"},"required":false,"name":"variables","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2000,"default":500},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Filas.","content":{"application/json":{"schema":{"type":"object","properties":{"anio":{"type":"string"},"variables":{"type":"array","items":{"type":"string"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["anio","variables","total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/saic/descarga/{anio}":{"get":{"tags":["inegi"],"operationId":"inegi_saic_descarga","summary":"Descargar un año censal completo del SAIC en Parquet (todas las variables)","parameters":[{"schema":{"type":"string","pattern":"^\\d{4}$"},"required":true,"name":"anio","in":"path"}],"responses":{"200":{"description":"Parquet."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg":{"get":{"tags":["inegi"],"operationId":"inegi_mg_resumen","summary":"Marco Geoestadístico 2025 completo: capas, conteos y verificación","description":"El Marco Geoestadístico 2025 del INEGI (versión por área geoestadística estatal, corte julio 2025) íntegro: entidades, municipios, localidades amanzanadas y rurales puntuales, AGEB urbanas y rurales, manzanas, caserío disperso, territorio insular, polígonos externos, ejes de vialidad, frentes de manzana y servicios (área, línea, punto). Cada capa se descarga como Parquet nacional (atributos + geometría WKB en el CRS original, ITRF2008 / Cónica Conforme de Lambert) y cada estado como el zip original del INEGI. `verificacion` compara los objetos obtenidos con los totales nacionales que el INEGI declara en el producto (contenido.txt).","responses":{"200":{"description":"Resumen.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"edicion":{"type":"string"},"titulo":{"type":"string"},"corte":{"type":"string"},"zip_nacional_url":{"type":"string"},"bytes_zip":{"type":"integer"},"verificacion":{"type":"object","additionalProperties":{"type":"object","properties":{"obtenido":{"type":"integer"},"publicado":{"type":"integer"}},"required":["obtenido","publicado"]}},"capas":{"type":"array","items":{"type":"object","properties":{"edicion":{"type":"string"},"capa":{"type":"string"},"nombre":{"type":"string"},"descripcion":{"type":"string"},"geometria":{"type":"string"},"crs":{"type":"string"},"campos":{"type":"array","items":{"type":"string"}},"entidades":{"type":"integer"},"objetos":{"type":"integer"},"publicado":{"type":["integer","null"]},"bytes_parquet":{"type":"integer"},"parquet_url":{"type":"string"}},"required":["edicion","capa","nombre","descripcion","geometria","crs","campos","entidades","objetos","publicado","bytes_parquet","parquet_url"]}},"estados_url":{"type":"string"}},"required":["fuente","fuente_url","edicion","titulo","corte","zip_nacional_url","bytes_zip","verificacion","capas","estados_url"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg/estados":{"get":{"tags":["inegi"],"operationId":"inegi_mg_estados","summary":"Los 32 zips estatales originales del Marco Geoestadístico 2025","responses":{"200":{"description":"Estados.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"cve_ent":{"type":"string"},"archivo":{"type":"string"},"bytes":{"type":"integer"},"url":{"type":"string"}},"required":["cve_ent","archivo","bytes","url"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg/capas/{capa}":{"get":{"tags":["inegi"],"operationId":"inegi_mg_capa","summary":"Una capa del Marco Geoestadístico con sus objetos por entidad","parameters":[{"schema":{"type":"string"},"required":true,"name":"capa","in":"path"}],"responses":{"200":{"description":"Capa.","content":{"application/json":{"schema":{"type":"object","properties":{"edicion":{"type":"string"},"capa":{"type":"string"},"nombre":{"type":"string"},"descripcion":{"type":"string"},"geometria":{"type":"string"},"crs":{"type":"string"},"campos":{"type":"array","items":{"type":"string"}},"entidades":{"type":"integer"},"objetos":{"type":"integer"},"publicado":{"type":["integer","null"]},"bytes_parquet":{"type":"integer"},"parquet_url":{"type":"string"},"por_entidad":{"type":"array","items":{"type":"object","properties":{"cve_ent":{"type":"string"},"objetos":{"type":"integer"}},"required":["cve_ent","objetos"]}}},"required":["edicion","capa","nombre","descripcion","geometria","crs","campos","entidades","objetos","publicado","bytes_parquet","parquet_url","por_entidad"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg/descarga/nacional":{"get":{"tags":["inegi"],"operationId":"inegi_mg_descarga_nacional","summary":"Descargar el zip nacional íntegro del Marco Geoestadístico 2025 (2.9 GB, tal como lo publica el INEGI)","responses":{"200":{"description":"Zip."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg/descarga/estado/{cve_ent}":{"get":{"tags":["inegi"],"operationId":"inegi_mg_descarga_estado","summary":"Descargar el zip original del INEGI de una entidad (16 capas SHAPE, catálogos y metadatos)","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"cve_ent","in":"path"}],"responses":{"200":{"description":"Zip."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/inegi/mg/descarga/{capa}":{"get":{"tags":["inegi"],"operationId":"inegi_mg_descarga_capa","summary":"Descargar una capa nacional del Marco Geoestadístico en Parquet (geometría WKB)","parameters":[{"schema":{"type":"string"},"required":true,"name":"capa","in":"path"}],"responses":{"200":{"description":"Parquet."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/ediciones":{"get":{"tags":["denue"],"operationId":"denue_ediciones","summary":"Las 25 ediciones del DENUE (2010 a 05/2026) y su verificación","description":"Cada edición de la descarga masiva del INEGI (archivos por entidad) con el total de unidades de sus archivos, la cifra que el INEGI publicó para esa edición (comunicado o documento metodológico) y la diferencia. `verificado` es true cuando coinciden, false cuando no (esas ediciones no entran en los cubos) y null cuando el INEGI no publicó una cifra exacta. `parquet_url` descarga la edición completa (todas las columnas) en Parquet.","responses":{"200":{"description":"Ediciones del DENUE.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"edicion":{"type":"string"},"periodo_inegi":{"type":"string"},"orden":{"type":"integer"},"unidades":{"type":"integer"},"publicado":{"type":["integer","null"]},"diferencia":{"type":["integer","null"]},"verificado":{"type":["boolean","null"]},"grupos":{"type":"integer"},"municipios":{"type":"integer"},"clases":{"type":"integer"},"archivos":{"type":"integer"},"scian":{"type":"string"},"fuente_cifra":{"type":["string","null"]},"parquet_url":{"type":"string"},"fuentes_prefijo":{"type":"string"}},"required":["edicion","periodo_inegi","orden","unidades","publicado","diferencia","verificado","grupos","municipios","clases","archivos","scian","fuente_cifra","parquet_url","fuentes_prefijo"]}}},"required":["fuente","fuente_url","n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/historico":{"get":{"tags":["denue"],"operationId":"denue_historico","summary":"Unidades económicas por edición del DENUE (serie 2010-2026)","description":"Total de unidades económicas en cada edición del DENUE, con filtros opcionales: `cve_ent` (2 dígitos), `codigo_act` (código SCIAN completo o prefijo de 2 a 5 dígitos; el DENUE de 2010 a 10/2013 usa el SCIAN 2007, de 2015 a 03/2018 el SCIAN 2013 y de 11/2018 en adelante el SCIAN 2018) y `per_ocu_cod` (estrato 1 = 0 a 5 personas … 7 = 251 y más; 0 = no especificado). Incluye todas las ediciones y marca `verificado`.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"cve_ent","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2,6}$"},"required":false,"name":"codigo_act","in":"query"},{"schema":{"type":"integer","minimum":0,"maximum":7},"required":false,"name":"per_ocu_cod","in":"query"}],"responses":{"200":{"description":"Serie por edición.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"filtros":{"type":"object","properties":{"cve_ent":{"type":["string","null"]},"codigo_act":{"type":["string","null"]},"per_ocu_cod":{"type":["integer","null"]}},"required":["cve_ent","codigo_act","per_ocu_cod"]},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"edicion":{"type":"string"},"periodo_inegi":{"type":"string"},"verificado":{"type":["boolean","null"]},"unidades":{"type":"integer"}},"required":["edicion","periodo_inegi","verificado","unidades"]}}},"required":["fuente","filtros","n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/denue/historico/descarga/{edicion}":{"get":{"tags":["denue"],"operationId":"denue_historico_descarga","summary":"Descargar una edición completa del DENUE en Parquet","description":"Devuelve el archivo Parquet de la edición (todas las unidades con sus columnas originales, tal como las publica el INEGI), desde el almacén del observatorio.","parameters":[{"schema":{"type":"string","pattern":"^\\d{4}(-\\d{2})?$"},"required":true,"name":"edicion","in":"path"}],"responses":{"200":{"description":"Archivo Parquet."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/resumen":{"get":{"tags":["anuies"],"operationId":"anuies_resumen","summary":"Qué tenemos del Anuario ANUIES","description":"Resumen verificable: ciclos cargados con sus filas, instituciones y totales nacionales (matrícula, nuevo ingreso, egresados, lugares ofertados, titulados y solicitudes), la conciliación de cada ciclo contra el agregado nacional del propio servicio de ANUIES, y las 167 cifras disponibles por programa. Fuente: anuario.anuies.mx.","responses":{"200":{"description":"Resumen.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"ciclos":{"type":"integer"},"primer_ciclo":{"type":["string","null"]},"ultimo_ciclo":{"type":["string","null"]},"filas":{"type":"integer"},"instituciones":{"type":"integer"},"cifras_por_programa":{"type":"integer"},"dimensiones":{"type":"array","items":{"type":"string"}},"por_ciclo":{"type":"array","items":{"type":"object","properties":{"ciclo":{"type":"string"},"filas":{"type":"integer"},"paginas":{"type":"integer"},"descargado_en":{"type":"string"},"conciliacion":{"type":"string"},"mat_total":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"edad_filas":{"type":"integer"},"procedencia_filas":{"type":"integer"},"instituciones":{"type":"integer"},"sha256":{"type":"string"},"bytes":{"type":"integer"},"parquet_clave":{"type":["string","null"]},"parquet_bytes":{"type":["integer","null"]},"parquet_url":{"type":["string","null"]}},"required":["ciclo","filas","paginas","descargado_en","conciliacion","mat_total","ni","e","lo_real","t","sni","edad_filas","procedencia_filas","instituciones","sha256","bytes","parquet_clave","parquet_bytes","parquet_url"]}}},"required":["fuente","fuente_url","ciclos","primer_ciclo","ultimo_ciclo","filas","instituciones","cifras_por_programa","dimensiones","por_ciclo"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/ciclos":{"get":{"tags":["anuies"],"operationId":"anuies_ciclos","summary":"Ciclos cargados","description":"Un registro por ciclo escolar con filas, totales nacionales, conciliación, huella del origen y el Parquet descargable.","responses":{"200":{"description":"Ciclos.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"ciclo":{"type":"string"},"filas":{"type":"integer"},"paginas":{"type":"integer"},"descargado_en":{"type":"string"},"conciliacion":{"type":"string"},"mat_total":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"edad_filas":{"type":"integer"},"procedencia_filas":{"type":"integer"},"instituciones":{"type":"integer"},"sha256":{"type":"string"},"bytes":{"type":"integer"},"parquet_clave":{"type":["string","null"]},"parquet_bytes":{"type":["integer","null"]},"parquet_url":{"type":["string","null"]}},"required":["ciclo","filas","paginas","descargado_en","conciliacion","mat_total","ni","e","lo_real","t","sni","edad_filas","procedencia_filas","instituciones","sha256","bytes","parquet_clave","parquet_bytes","parquet_url"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/columnas":{"get":{"tags":["anuies"],"operationId":"anuies_columnas","summary":"Las 167 cifras por programa y qué significan","description":"Clave (la de ANUIES en minúsculas), título, grupo (total, sexo, edad, disc, hli, procedencia) y en qué tabla vive (programas, programas_edad, programas_procedencia).","responses":{"200":{"description":"Columnas.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"titulo":{"type":"string"},"grupo":{"type":"string"},"tabla":{"type":"string"}},"required":["clave","titulo","grupo","tabla"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/valores":{"get":{"tags":["anuies"],"operationId":"anuies_valores","summary":"Valores distintos de una dimensión","description":"Los valores que toma una dimensión en un ciclo (el último si no se indica), con cuántos programas y cuánta matrícula tiene cada uno. Sirve para armar filtros exactos.","parameters":[{"schema":{"type":"string","enum":["entidad","municipio","sostenimiento","clasificacion","institucion","escuela","nivel","modalidad","campo_amplio","campo_especifico","campo_detallado","campo_unitario","carrera"]},"required":true,"name":"dimension","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"}],"responses":{"200":{"description":"Valores.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"dimension":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"mat_total":{"type":["integer","null"]}},"required":["valor","programas","mat_total"]}}},"required":["ciclo","dimension","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/instituciones":{"get":{"tags":["anuies"],"operationId":"anuies_instituciones","summary":"Buscar instituciones","description":"Las instituciones del anuario con su clave estable (nombre sin acentos, en minúsculas y con guiones), nombre, sostenimiento y clasificación (del último ciclo en que aparecen), en qué ciclos están y sus cifras del último ciclo. `q` busca por contenido (sin acentos ni mayúsculas). Orden: matrícula descendente.","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Instituciones.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"sostenimiento":{"type":["string","null"]},"clasificacion":{"type":["string","null"]},"primer_ciclo":{"type":"string"},"ultimo_ciclo":{"type":"string"},"ciclos":{"type":"integer"},"entidades":{"type":"integer"},"escuelas":{"type":"integer"},"programas":{"type":"integer"},"mat_total":{"type":"integer"},"ni":{"type":"integer"},"e":{"type":"integer"},"t":{"type":"integer"}},"required":["clave","nombre","sostenimiento","clasificacion","primer_ciclo","ultimo_ciclo","ciclos","entidades","escuelas","programas","mat_total","ni","e","t"]}}},"required":["total","n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/instituciones/{clave}":{"get":{"tags":["anuies"],"operationId":"anuies_institucion","summary":"Una institución y su serie completa","description":"La ficha de la institución y su serie ciclo por ciclo (programas, escuelas y las 31 cifras base sumadas). Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string"},"required":true,"name":"clave","in":"path"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Institución.","content":{"application/json":{"schema":{"type":"object","properties":{"institucion":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"sostenimiento":{"type":["string","null"]},"clasificacion":{"type":["string","null"]},"primer_ciclo":{"type":"string"},"ultimo_ciclo":{"type":"string"},"ciclos":{"type":"integer"},"entidades":{"type":"integer"},"escuelas":{"type":"integer"},"programas":{"type":"integer"},"mat_total":{"type":"integer"},"ni":{"type":"integer"},"e":{"type":"integer"},"t":{"type":"integer"}},"required":["clave","nombre","sostenimiento","clasificacion","primer_ciclo","ultimo_ciclo","ciclos","entidades","escuelas","programas","mat_total","ni","e","t"]},"serie":{"type":"array","items":{"type":"object","properties":{"ciclo":{"type":"string"},"programas":{"type":"integer"},"escuelas":{"type":"integer"},"instituciones":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["ciclo","programas","escuelas","instituciones","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["institucion","serie"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/serie":{"get":{"tags":["anuies"],"operationId":"anuies_serie","summary":"Serie nacional (o filtrada) ciclo por ciclo","description":"Suma de las cifras base por ciclo para todo el país o para el subconjunto que definan los filtros (por ejemplo `nivel=DOCTORADO` o `entidad=JALISCO`); `institucion` acepta la clave de una institución. Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Serie.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"ciclo":{"type":"string"},"programas":{"type":"integer"},"escuelas":{"type":"integer"},"instituciones":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["ciclo","programas","escuelas","instituciones","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/agregado":{"get":{"tags":["anuies"],"operationId":"anuies_agregado","summary":"Agregar un ciclo por una dimensión","description":"Para un ciclo (el último si no se indica), suma las cifras base agrupando por la dimensión `por` (nivel por defecto): entidad, municipio, sostenimiento, clasificacion, institucion, escuela, nivel, modalidad, campo_amplio, campo_especifico, campo_detallado, campo_unitario o carrera. Con `institucion` se limita a una institución (así salen sus planteles, sus carreras o sus campos de formación). Orden: matrícula descendente. Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string","enum":["entidad","municipio","sostenimiento","clasificacion","institucion","escuela","nivel","modalidad","campo_amplio","campo_especifico","campo_detallado","campo_unitario","carrera"]},"required":false,"name":"por","in":"query"},{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/procedencia":{"get":{"tags":["anuies"],"operationId":"anuies_procedencia","summary":"Procedencia del nuevo ingreso por entidad y región","description":"De dónde vienen las personas de nuevo ingreso de un ciclo: las 32 entidades (con su clave INEGI) y 8 regiones del extranjero, sumadas sobre los programas que cumplen los filtros. `suma_procedencia` puede diferir de `ni_total` cuando la institución no reporta procedencia para todos sus programas. Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Procedencia.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"ni_total":{"type":["integer","null"]},"programas_con_dato":{"type":"integer"},"suma_procedencia":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"nombre":{"type":"string"},"entidad":{"type":["string","null"]},"ni":{"type":["integer","null"]}},"required":["codigo","nombre","entidad","ni"]}}},"required":["ciclo","ni_total","programas_con_dato","suma_procedencia","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/edades":{"get":{"tags":["anuies"],"operationId":"anuies_edades","summary":"Matrícula y nuevo ingreso por edad y sexo","description":"Los 16 grupos de edad de ANUIES (17 a 29 año por año, 30 a 34, 35 a 39, 40 y más) con matrícula y nuevo ingreso por sexo, sumados sobre los programas que cumplen los filtros de un ciclo. Las sumas por edad pueden quedar por debajo del total cuando no todos los programas reportan edad. Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Edades.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"mat_total":{"type":["integer","null"]},"ni_total":{"type":["integer","null"]},"programas_con_dato":{"type":"integer"},"suma_matricula_edades":{"type":"integer"},"suma_ni_edades":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"grupo":{"type":"string"},"matricula_m":{"type":["integer","null"]},"matricula_h":{"type":["integer","null"]},"matricula":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]}},"required":["grupo","matricula_m","matricula_h","matricula","ni_m","ni_h","ni"]}}},"required":["ciclo","mat_total","ni_total","programas_con_dato","suma_matricula_edades","suma_ni_edades","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/programas":{"get":{"tags":["anuies"],"operationId":"anuies_programas","summary":"Programas fila por fila","description":"Las filas del anuario tal cual (un programa en una escuela, ciclo, nivel y modalidad) con sus 31 cifras base. Paginación por llave: `limit` (hasta 1000) y `after` (el `id` de la última fila recibida; la respuesta trae `next_after`). Sin filtros recorre todo el anuario ordenado por id (ciclo, luego orden de ANUIES). Los filtros (`entidad`, `sostenimiento`, `clasificacion`, `escuela`, `nivel`, `modalidad`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`) son valores exactos tal como los escribe ANUIES (en mayúsculas; los campos de formación con mayúscula inicial); `q` busca por contenido en carrera y escuela. Los valores válidos de cada dimensión están en `/api/v1/anuies/valores`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"institucion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sostenimiento","in":"query"},{"schema":{"type":"string"},"required":false,"name":"clasificacion","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0},"required":false,"name":"after","in":"query"}],"responses":{"200":{"description":"Programas.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"n":{"type":"integer"},"next_after":{"type":["integer","null"]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"ciclo":{"type":"string"},"entidad":{"type":"string"},"municipio":{"type":["string","null"]},"sostenimiento":{"type":["string","null"]},"anuies":{"type":["integer","null"]},"clasificacion":{"type":["string","null"]},"institucion":{"type":"string"},"institucion_clave":{"type":"string"},"escuela":{"type":["string","null"]},"nivel":{"type":["string","null"]},"modalidad":{"type":["string","null"]},"campo_amplio":{"type":["string","null"]},"campo_especifico":{"type":["string","null"]},"campo_detallado":{"type":["string","null"]},"campo_unitario":{"type":["string","null"]},"carrera":{"type":["string","null"]},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["id","ciclo","entidad","municipio","sostenimiento","anuies","clasificacion","institucion","institucion_clave","escuela","nivel","modalidad","campo_amplio","campo_especifico","campo_detallado","campo_unitario","carrera","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["total","n","next_after","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/programas/{id}":{"get":{"tags":["anuies"],"operationId":"anuies_programa","summary":"Un programa con todas sus cifras","description":"La fila completa: cifras base, desagregación por edad (96 columnas) y procedencia del nuevo ingreso (40), o `null` en las tablas donde ANUIES no reporta nada para ese programa.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Programa.","content":{"application/json":{"schema":{"type":"object","properties":{"programa":{"type":"object","properties":{"id":{"type":"integer"},"ciclo":{"type":"string"},"entidad":{"type":"string"},"municipio":{"type":["string","null"]},"sostenimiento":{"type":["string","null"]},"anuies":{"type":["integer","null"]},"clasificacion":{"type":["string","null"]},"institucion":{"type":"string"},"institucion_clave":{"type":"string"},"escuela":{"type":["string","null"]},"nivel":{"type":["string","null"]},"modalidad":{"type":["string","null"]},"campo_amplio":{"type":["string","null"]},"campo_especifico":{"type":["string","null"]},"campo_detallado":{"type":["string","null"]},"campo_unitario":{"type":["string","null"]},"carrera":{"type":["string","null"]},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["id","ciclo","entidad","municipio","sostenimiento","anuies","clasificacion","institucion","institucion_clave","escuela","nivel","modalidad","campo_amplio","campo_especifico","campo_detallado","campo_unitario","carrera","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]},"edad":{"type":["object","null"],"additionalProperties":{"type":["integer","null"]}},"procedencia":{"type":["object","null"],"additionalProperties":{"type":["integer","null"]}}},"required":["programa","edad","procedencia"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/anuies/descarga/*":{"get":{"tags":["anuies"],"operationId":"anuies_descarga","summary":"Descargar el Parquet de un ciclo","description":"Entrega el archivo tal como está en el almacén (R2): un Parquet por ciclo con las 14 dimensiones, el ciclo y las 167 cifras (enteros; nulo donde ANUIES no da la columna). Las claves están en `parquet_clave` de /api/v1/anuies/ciclos (prefijo `anuies/`).","parameters":[{"schema":{"type":"string"},"required":true,"name":"clave","in":"path"}],"responses":{"200":{"description":"El archivo."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/resumen":{"get":{"tags":["unam"],"operationId":"unam_resumen","summary":"Qué tenemos de la UNAM","description":"Las dos fuentes: el Concurso de Selección (años, concursos, carrera-plantel con encabezado y con distribución completa, personas con calificación recuperada, cobertura frente al universo oficial) y la UNAM en el Anuario ANUIES (ciclos, planteles, programas y cifras del último ciclo).","responses":{"200":{"description":"Resumen.","content":{"application/json":{"schema":{"type":"object","properties":{"concurso":{"type":"object","properties":{"fuente":{"type":"string"},"licencia":{"type":"string"},"anios":{"type":"array","items":{"type":"integer"}},"concursos":{"type":"array","items":{"type":"string"}},"carrera_plantel_con_encabezado":{"type":"integer"},"carrera_plantel_con_distribucion":{"type":"integer"},"personas_con_calificacion":{"type":["integer","null"]},"universo_carrera_plantel":{"type":"integer"},"archivos":{"type":"integer"}},"required":["fuente","licencia","anios","concursos","carrera_plantel_con_encabezado","carrera_plantel_con_distribucion","personas_con_calificacion","universo_carrera_plantel","archivos"]},"anuario":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"institucion":{"type":["object","null"],"additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}},"ultimo_ciclo":{"type":["string","null"]},"matricula_ultimo_ciclo":{"type":["integer","null"]}},"required":["fuente","fuente_url","institucion","ultimo_ciclo","matricula_ultimo_ciclo"]}},"required":["concurso","anuario"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/concurso/encabezados":{"get":{"tags":["unam"],"operationId":"unam_concurso_encabezados","summary":"Encabezados oficiales por carrera-plantel-concurso","description":"Una fila por carrera-plantel-concurso con lo que la DGAE publica encima de cada listado: oferta, aspirantes, personas que presentaron, aciertos mínimos (el corte) y seleccionadas; más fuente, cobertura de la página y huella del original. `area` 1-4 (I Físico-Matemáticas e Ingenierías · II Biológicas, Químicas y de la Salud · III Sociales · IV Humanidades y Artes). El código de carrera cambió de ancho en 2019: para series largas use carrera + plantel.","parameters":[{"schema":{"type":"string"},"required":false,"name":"anio","in":"query"},{"schema":{"type":"string","enum":["febrero","junio","noviembre","licenciatura"]},"required":false,"name":"concurso","in":"query"},{"schema":{"type":"string","enum":["escolarizado","abierta","a distancia"]},"required":false,"name":"sistema","in":"query"},{"schema":{"type":"string"},"required":false,"name":"area","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera_codigo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"plantel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":2000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Encabezados.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}}}},"required":["total","n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/concurso/distribucion/{anio}/{concurso}/{carrera_codigo}":{"get":{"tags":["unam"],"operationId":"unam_concurso_distribucion","summary":"Histograma de aciertos de una carrera-plantel-concurso","description":"Cuántas personas obtuvieron cada número de aciertos (0-120) en un concurso, sistema y código de carrera-plantel, con el encabezado oficial al lado para cotejar (la suma del histograma debe coincidir con las personas que presentaron cuando la página está completa).","parameters":[{"schema":{"type":"string"},"required":true,"name":"anio","in":"path"},{"schema":{"type":"string","enum":["febrero","junio","noviembre","licenciatura"]},"required":true,"name":"concurso","in":"path"},{"schema":{"type":"string"},"required":true,"name":"carrera_codigo","in":"path"},{"schema":{"type":"string","enum":["escolarizado","abierta","a distancia"]},"required":false,"name":"sistema","in":"query"}],"responses":{"200":{"description":"Distribución.","content":{"application/json":{"schema":{"type":"object","properties":{"anio":{"type":"integer"},"concurso":{"type":"string"},"carrera_codigo":{"type":"string"},"encabezados":{"type":"array","items":{"type":"object","additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}}},"personas":{"type":["integer","null"]},"items":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"aciertos":{"type":"integer"},"n":{"type":"integer"},"fuente":{"type":["string","null"]}},"required":["sistema","aciertos","n","fuente"]}}},"required":["anio","concurso","carrera_codigo","encabezados","personas","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/concurso/universo":{"get":{"tags":["unam"],"operationId":"unam_concurso_universo","summary":"El universo oficial de carrera-plantel por concurso","description":"Qué carrera-plantel existieron en cada concurso según los índices por área de la DGAE: el denominador de la cobertura.","parameters":[{"schema":{"type":"string"},"required":false,"name":"anio","in":"query"},{"schema":{"type":"string","enum":["febrero","junio","noviembre","licenciatura"]},"required":false,"name":"concurso","in":"query"},{"schema":{"type":"string","enum":["escolarizado","abierta","a distancia"]},"required":false,"name":"sistema","in":"query"},{"schema":{"type":"string"},"required":false,"name":"area","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":3000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Universo.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}}}},"required":["total","n","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/concurso/tablas/{tabla}":{"get":{"tags":["unam"],"operationId":"unam_concurso_tabla","summary":"Cualquier tabla del dataset del concurso","description":"Lectura directa de una de las tablas del dataset (cobertura, proceso, demanda_licenciatura, identidad_doble, cola_baja, sesgo_cobertura, sesgo_demanda, paginas, intentos_acceso, cronologia_2026, cronologia_terceros, carreras_identidad, avisos, proceso_2026, además de encabezados, distribucion y universo) con filtros opcionales por `anio`, `concurso` y `sistema` cuando la tabla tiene esas columnas. El significado de cada columna está en el diccionario (/api/v1/unam/concurso/archivos).","parameters":[{"schema":{"type":"string","enum":["encabezados","distribucion","universo","cobertura","proceso","demanda_licenciatura","identidad_doble","cola_baja","sesgo_cobertura","sesgo_demanda","paginas","intentos_acceso","cronologia_2026","cronologia_terceros","carreras_identidad","avisos","proceso_2026"]},"required":true,"name":"tabla","in":"path"},{"schema":{"type":"string"},"required":false,"name":"anio","in":"query"},{"schema":{"type":"string","enum":["febrero","junio","noviembre","licenciatura"]},"required":false,"name":"concurso","in":"query"},{"schema":{"type":"string","enum":["escolarizado","abierta","a distancia"]},"required":false,"name":"sistema","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Filas.","content":{"application/json":{"schema":{"type":"object","properties":{"tabla":{"type":"string"},"columnas":{"type":"array","items":{"type":"string"}},"total":{"type":"integer"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}}}},"required":["tabla","columnas","total","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/concurso/archivos":{"get":{"tags":["unam"],"operationId":"unam_concurso_archivos","summary":"Los archivos del dataset, con huella y descarga","description":"CSV del dataset, diccionario de datos y licencia (CC BY 4.0) tal como se publican, con filas, bytes, SHA-256 y URL de descarga en el observatorio.","responses":{"200":{"description":"Archivos.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"archivo":{"type":"string"},"tabla":{"type":["string","null"]},"filas":{"type":["integer","null"]},"bytes":{"type":"integer"},"sha256":{"type":"string"},"clave_r2":{"type":"string"},"url":{"type":"string"},"cargado_en":{"type":"string"}},"required":["archivo","tabla","filas","bytes","sha256","clave_r2","url","cargado_en"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/descarga/*":{"get":{"tags":["unam"],"operationId":"unam_descarga","summary":"Descargar un archivo del dataset del concurso","description":"Entrega el archivo tal como está en el almacén (prefijo `unam/`); las claves están en /api/v1/unam/concurso/archivos.","parameters":[{"schema":{"type":"string"},"required":true,"name":"clave","in":"path"}],"responses":{"200":{"description":"El archivo."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/serie":{"get":{"tags":["unam"],"operationId":"unam_anuario_serie","summary":"La UNAM ciclo por ciclo (2000-2001 en adelante)","description":"Matrícula, nuevo ingreso, egresados, lugares ofertados, titulados y solicitudes por sexo, sumados por ciclo sobre los programas de la UNAM que cumplan los filtros (por ejemplo `nivel=LICENCIATURA UNIVERSITARIA Y TECNOLÓGICA`). Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Serie.","content":{"application/json":{"schema":{"type":"object","properties":{"institucion":{"type":"object","additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"ciclo":{"type":"string"},"programas":{"type":"integer"},"escuelas":{"type":"integer"},"instituciones":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["ciclo","programas","escuelas","instituciones","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["institucion","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/planteles":{"get":{"tags":["unam"],"operationId":"unam_anuario_planteles","summary":"Planteles de la UNAM en un ciclo","description":"Cada escuela, facultad, campus o instituto de la UNAM con sus cifras del ciclo (el último si no se indica), en orden de matrícula. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/carreras":{"get":{"tags":["unam"],"operationId":"unam_anuario_carreras","summary":"Carreras y posgrados de la UNAM en un ciclo","description":"Cada programa (licenciatura, especialidad, maestría o doctorado) sumado sobre todos los planteles donde se imparte, en orden de matrícula. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/campos":{"get":{"tags":["unam"],"operationId":"unam_anuario_campos","summary":"Campos de formación de la UNAM en un ciclo","description":"Las cifras por campo amplio de formación (clasificación mexicana de programas de estudio), para comparar matrícula y egreso por área y sexo. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/niveles":{"get":{"tags":["unam"],"operationId":"unam_anuario_niveles","summary":"Niveles de la UNAM en un ciclo","description":"Técnico superior, licenciatura, especialidad, maestría y doctorado con sus cifras del ciclo. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/agregado":{"get":{"tags":["unam"],"operationId":"unam_anuario_agregado","summary":"La UNAM agregada por cualquier dimensión","description":"Agrupa las cifras de la UNAM en un ciclo por la dimensión `por` (entidad, municipio, escuela, nivel, modalidad, campo_amplio, campo_especifico, campo_detallado, campo_unitario o carrera). Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string","enum":["entidad","municipio","sostenimiento","clasificacion","institucion","escuela","nivel","modalidad","campo_amplio","campo_especifico","campo_detallado","campo_unitario","carrera"]},"required":false,"name":"por","in":"query"},{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Agregado.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"por":{"type":"string"},"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"valor":{"type":["string","null"]},"programas":{"type":"integer"},"m_m":{"type":["integer","null"]},"m_h":{"type":["integer","null"]},"mat_total":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]},"e_m":{"type":["integer","null"]},"e_h":{"type":["integer","null"]},"e":{"type":["integer","null"]},"lo_real":{"type":["integer","null"]},"t_m":{"type":["integer","null"]},"t_h":{"type":["integer","null"]},"t":{"type":["integer","null"]},"sni_m":{"type":["integer","null"]},"sni_h":{"type":["integer","null"]},"sni":{"type":["integer","null"]},"m_m_i":{"type":["integer","null"]},"m_h_i":{"type":["integer","null"]},"m_i":{"type":["integer","null"]},"m_m_d":{"type":["integer","null"]},"m_h_d":{"type":["integer","null"]},"mat_d":{"type":["integer","null"]},"m_i_d":{"type":["integer","null"]},"ni_d":{"type":["integer","null"]},"ni_i":{"type":["integer","null"]},"e_d":{"type":["integer","null"]},"e_i":{"type":["integer","null"]},"t_d":{"type":["integer","null"]},"t_i":{"type":["integer","null"]},"sni_d":{"type":["integer","null"]},"sni_i":{"type":["integer","null"]}},"required":["valor","programas","m_m","m_h","mat_total","ni_m","ni_h","ni","e_m","e_h","e","lo_real","t_m","t_h","t","sni_m","sni_h","sni","m_m_i","m_h_i","m_i","m_m_d","m_h_d","mat_d","m_i_d","ni_d","ni_i","e_d","e_i","t_d","t_i","sni_d","sni_i"]}}},"required":["ciclo","por","n","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/procedencia":{"get":{"tags":["unam"],"operationId":"unam_anuario_procedencia","summary":"De dónde viene el nuevo ingreso de la UNAM","description":"Personas de nuevo ingreso por entidad de procedencia (32, con clave INEGI) y región del extranjero (8) en un ciclo. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Procedencia.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"ni_total":{"type":["integer","null"]},"programas_con_dato":{"type":"integer"},"suma_procedencia":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"nombre":{"type":"string"},"entidad":{"type":["string","null"]},"ni":{"type":["integer","null"]}},"required":["codigo","nombre","entidad","ni"]}}},"required":["ciclo","ni_total","programas_con_dato","suma_procedencia","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/unam/anuario/edades":{"get":{"tags":["unam"],"operationId":"unam_anuario_edades","summary":"Edades de la matrícula y del nuevo ingreso de la UNAM","description":"Los 16 grupos de edad de ANUIES con matrícula y nuevo ingreso por sexo en un ciclo. Filtros exactos como los escribe ANUIES (`nivel`, `modalidad`, `escuela`, `campo_amplio`, `campo_especifico`, `campo_detallado`, `carrera`, `entidad`); `q` busca por contenido en carrera y escuela; valores válidos en /api/v1/anuies/valores?institucion=universidad-nacional-autonoma-de-mexico.","parameters":[{"schema":{"type":"string"},"required":false,"name":"ciclo","in":"query"},{"schema":{"type":"string"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"escuela","in":"query"},{"schema":{"type":"string"},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string"},"required":false,"name":"modalidad","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_amplio","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_especifico","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campo_detallado","in":"query"},{"schema":{"type":"string"},"required":false,"name":"carrera","in":"query"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Edades.","content":{"application/json":{"schema":{"type":"object","properties":{"ciclo":{"type":"string"},"mat_total":{"type":["integer","null"]},"ni_total":{"type":["integer","null"]},"programas_con_dato":{"type":"integer"},"suma_matricula_edades":{"type":"integer"},"suma_ni_edades":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"grupo":{"type":"string"},"matricula_m":{"type":["integer","null"]},"matricula_h":{"type":["integer","null"]},"matricula":{"type":["integer","null"]},"ni_m":{"type":["integer","null"]},"ni_h":{"type":["integer","null"]},"ni":{"type":["integer","null"]}},"required":["grupo","matricula_m","matricula_h","matricula","ni_m","ni_h","ni"]}}},"required":["ciclo","mat_total","ni_total","programas_con_dato","suma_matricula_edades","suma_ni_edades","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/censo2020/resumen":{"get":{"tags":["censo2020"],"operationId":"censo2020_resumen","summary":"Qué tenemos del Censo 2020 por localidad","description":"Resumen verificable del ITER 2020 cargado: edición, filas por nivel (nacional, entidades, municipios, localidades y resúmenes de localidades de una y dos viviendas, que existen en los tres niveles), número de indicadores y población total nacional, estatal por suma y municipal por suma (deben coincidir con la cifra oficial del Censo: 126,014,024 habitantes).","responses":{"200":{"description":"Resumen del ITER 2020.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"edicion":{"type":["string","null"]},"indicadores":{"type":"integer"},"filas":{"type":"integer"},"por_nivel":{"type":"object","additionalProperties":{"type":"integer"}},"poblacion_total_nacional":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"suma_entidades":{"type":["number","null"]},"suma_municipios":{"type":["number","null"]},"descargado_en":{"type":["string","null"]}},"required":["fuente","fuente_url","edicion","indicadores","filas","por_nivel","poblacion_total_nacional","suma_entidades","suma_municipios","descargado_en"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/censo2020/localidades":{"get":{"tags":["censo2020"],"operationId":"censo2020_localidades","summary":"Buscar localidades, municipios y entidades del Censo 2020","description":"Filas del ITER 2020 con sus campos principales (población total, femenina y masculina, hogares y viviendas). `q` busca en el nombre de la localidad (contiene, sin distinguir mayúsculas); `entidad` (2 dígitos) y `mun` (3 dígitos) filtran por clave; `nivel` elige el tipo de fila: nacional, entidad, municipio, localidad o resumen_1_2_viviendas (totales de localidades de una y dos viviendas, cuyos datos individuales el INEGI protege con '*'). Paginado con `limit` (1-1000) y `offset`; orden por clave geográfica.","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"string","pattern":"^\\d{3}$"},"required":false,"name":"mun","in":"query"},{"schema":{"type":"string","enum":["nacional","entidad","municipio","localidad","resumen_1_2_viviendas"]},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Filas que cumplen los filtros.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"nivel":{"type":"string"},"entidad":{"type":"string"},"nom_ent":{"type":["string","null"]},"mun":{"type":"string"},"nom_mun":{"type":["string","null"]},"loc":{"type":"string"},"nom_loc":{"type":["string","null"]},"longitud":{"type":["string","null"]},"latitud":{"type":["string","null"]},"altitud":{"type":["string","null"]},"pobtot":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"pobfem":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"pobmas":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"tothog":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"vivtot":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]},"tvivhab":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}},"required":["nivel","entidad","nom_ent","mun","nom_mun","loc","nom_loc","longitud","latitud","altitud","pobtot","pobfem","pobmas","tothog","vivtot","tvivhab"]}}},"required":["total","limit","offset","items"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/censo2020/localidades/{entidad}/{mun}/{loc}":{"get":{"tags":["censo2020"],"operationId":"censo2020_localidad","summary":"Los 286 indicadores de una localidad, municipio o entidad","description":"Fila completa del ITER 2020 para una clave geográfica: `entidad` (00 = nacional), `mun` (000 = total de la entidad) y `loc` (0000 = total del municipio). Devuelve las 286 columnas del INEGI con sus mnemónicos originales en minúsculas; '*' y 'N/D' se conservan como texto.","parameters":[{"schema":{"type":"string"},"required":true,"name":"entidad","in":"path"},{"schema":{"type":"string"},"required":true,"name":"mun","in":"path"},{"schema":{"type":"string"},"required":true,"name":"loc","in":"path"}],"responses":{"200":{"description":"Fila completa.","content":{"application/json":{"schema":{"type":"object","properties":{"nivel":{"type":"string"}},"required":["nivel"],"additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/censo2020/indicadores":{"get":{"tags":["censo2020"],"operationId":"censo2020_indicadores","summary":"Los 286 indicadores del ITER 2020 (diccionario del INEGI)","description":"Diccionario de datos del ITER 2020 tal como lo publica el INEGI: número, nombre, descripción, mnemónico, columna en esta API, rangos y longitud. `q` filtra por nombre o descripción (contiene, sin distinguir mayúsculas).","parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"Indicadores.","content":{"application/json":{"schema":{"type":"object","properties":{"n":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"num":{"type":"integer"},"indicador":{"type":["string","null"]},"descripcion":{"type":["string","null"]},"mnemonico":{"type":["string","null"]},"columna":{"type":["string","null"]},"rangos":{"type":["string","null"]},"longitud":{"type":["string","null"]}},"required":["num","indicador","descripcion","mnemonico","columna","rangos","longitud"]}}},"required":["n","items"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/censo2020/indicadores/{columna}":{"get":{"tags":["censo2020"],"operationId":"censo2020_indicador","summary":"Un indicador del Censo 2020 para todas las geografías de un nivel","description":"Valor de un indicador (columna del ITER, p. ej. `pobtot`, `p_60ymas`, `vph_inter`) para todas las filas de un `nivel` (por defecto municipio), opcionalmente dentro de una `entidad`. Es la consulta para mapas y comparaciones. Paginado con `limit` (1-5000) y `offset`; orden por clave geográfica.","parameters":[{"schema":{"type":"string"},"required":true,"name":"columna","in":"path"},{"schema":{"type":"string","enum":["nacional","entidad","municipio","localidad","resumen_1_2_viviendas"]},"required":false,"name":"nivel","in":"query"},{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":false,"name":"entidad","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":5000,"default":2500},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Valores del indicador.","content":{"application/json":{"schema":{"type":"object","properties":{"columna":{"type":"string"},"indicador":{"type":["string","null"]},"nivel":{"type":"string"},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"entidad":{"type":"string"},"nom_ent":{"type":["string","null"]},"mun":{"type":"string"},"nom_mun":{"type":["string","null"]},"loc":{"type":"string"},"nom_loc":{"type":["string","null"]},"valor":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"null"}]}},"required":["entidad","nom_ent","mun","nom_mun","loc","nom_loc","valor"]}}},"required":["columna","indicador","nivel","total","limit","offset","items"]}}}},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Parámetro inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/actual":{"get":{"tags":["clima"],"operationId":"clima_actual","summary":"Pronóstico de modelo para las 32 capitales (no es medición)","description":"Temperatura, humedad, viento y código de tiempo que da un MODELO numérico para el punto de cada observatorio oficial, con el instante de su intervalo. Fuente: Open-Meteo, que publica cada 15 minutos; el observatorio lo refresca cada 5 minutos en un solo pedido y verifica cada respuesta (32 de 32, intervalo reciente, coordenadas que coinciden). Desde noviembre de 2026 la medición es la del SMN (`/api/v1/clima/medicion`); esto es el pronóstico contra el que se calcula el error del modelo. Es el dato `datos-mexico/clima-capitales` del Protocolo DPM: con una fuente de 15 minutos queda fuera de clase, y así se publica.","responses":{"200":{"description":"Pronóstico de modelo.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"es":{"type":"string"},"relojes":{"type":"object","properties":{"fuente_ms":{"type":"integer"},"refresco_ms":{"type":"integer"},"ultimo_refresco":{"type":["string","null"]},"ultima_verificacion":{"type":["string","null"]}},"required":["fuente_ms","refresco_ms","ultimo_refresco","ultima_verificacion"]},"dpm":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"ficha":{"type":"string"}},"required":["sistema","dato","ficha"]},"capitales":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"estado":{"type":"string"},"capital":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"},"temperatura_c":{"type":["number","null"]},"humedad_pct":{"type":["number","null"]},"viento_kmh":{"type":["number","null"]},"codigo_tiempo":{"type":["integer","null"]},"tiempo_fuente":{"type":"string"},"verificado_en":{"type":["string","null"]}},"required":["clave","estado","capital","lat","lon","temperatura_c","humedad_pct","viento_kmh","codigo_tiempo","tiempo_fuente","verificado_en"]}}},"required":["fuente","fuente_url","es","relojes","dpm","capitales"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/comprobacion":{"get":{"tags":["clima"],"operationId":"clima_comprobacion","summary":"Comprobación de cara pública del pronóstico de modelo para el pulso DPM","description":"Responde cuándo fue el último refresco del pronóstico y cuántos hubo en la última hora, leído de la bitácora de refrescos. Es la dirección que el pulso consulta por su cuenta cada diez minutos para cotejar lo reportado.","responses":{"200":{"description":"Último refresco y refrescos de la última hora.","content":{"application/json":{"schema":{"type":"object","properties":{"ultimo_refresco":{"type":["string","null"]},"refrescos_ultima_hora":{"type":"integer"}},"required":["ultimo_refresco","refrescos_ultima_hora"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/estaciones":{"get":{"tags":["clima"],"operationId":"clima_estaciones","summary":"Las 32 capitales: observatorio oficial, aeropuerto testigo, récords y reglas de verificación","description":"Para cada capital, el observatorio sinóptico del SMN que la mide (número OMM, clave climatológica, coordenadas de OSCAR/Surface, distancia al centro urbano), su aeropuerto testigo (o por qué no tiene) y los récords mensuales con que se verifica cada lectura. Incluye las reglas de verificación en palabras. Generado con scripts/clima/generar_estaciones.py.","responses":{"200":{"description":"Estaciones y reglas.","content":{"application/json":{"schema":{"type":"object","properties":{"reglas":{"type":"object","additionalProperties":{}},"estaciones":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["reglas","estaciones"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/medicion":{"get":{"tags":["clima"],"operationId":"clima_medicion","summary":"Medición oficial vigente de las 32 capitales, con testigo, pronóstico, error del modelo y relojes","description":"Por capital: la última observación oficial del SMN (hora medida, hora en que el caché de la OMM la tuvo, hora en que llegó al observatorio, marcas de verificación y cotejo con el aeropuerto), el último METAR del aeropuerto testigo, el pronóstico de modelo vigente y el último error del modelo. Con el lote de la última hora (cuántas de 32 y cuáles faltan). Es el dato `datos-mexico/clima-estaciones` del Protocolo DPM: fuente cada hora, fuera de clase por la fuente.","responses":{"200":{"description":"Medición vigente.","content":{"application/json":{"schema":{"type":"object","properties":{"relojes":{"type":"object","additionalProperties":{}},"lote":{"type":["object","null"],"additionalProperties":{}},"dpm":{"type":"array","items":{"type":"object","additionalProperties":{}}},"capitales":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["relojes","lote","dpm","capitales"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/capitales/{clave}":{"get":{"tags":["clima"],"operationId":"clima_capital","summary":"Historia de una capital: medición oficial, modelo, error del modelo y aeropuerto","description":"Hasta 30 días (`dias`, por omisión 30) de observaciones horarias del SMN con sus marcas, el valor del modelo para cada hora y su error, el METAR del aeropuerto testigo y el resumen del error del modelo (n, error absoluto medio, sesgo).","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"clave","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":30},"required":false,"name":"dias","in":"query"}],"responses":{"200":{"description":"Historia.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/capitales/{clave}/mensaje-original":{"get":{"tags":["clima"],"operationId":"clima_mensaje_original","summary":"El mensaje BUFR original de una observación, para auditarla","description":"Devuelve el archivo tal como se leyó del caché de la OMM (base64), su dirección y su huella SHA-256. Cualquiera puede decodificarlo con ecCodes y comparar.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"clave","in":"path"},{"schema":{"type":"string"},"required":true,"name":"instante","in":"query"}],"responses":{"200":{"description":"Mensaje original.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/error-modelo":{"get":{"tags":["clima"],"operationId":"clima_error_modelo","summary":"Error del modelo: por capital, por hora del día y por mes","description":"Indicador propio del observatorio. Error = modelo − medición oficial del SMN, en temperatura (°C), humedad (puntos) y viento (m/s). Por capital en los últimos `dias` (por omisión 30), por hora local del día (UTC−6) y por mes, con n, error absoluto medio y sesgo. El modelo es Open-Meteo en el punto del observatorio, con el valor que daba para cada hora en la última consulta anterior a esa hora.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":365},"required":false,"name":"dias","in":"query"}],"responses":{"200":{"description":"Error del modelo.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/error-smn":{"get":{"tags":["clima"],"operationId":"clima_error_smn","summary":"Qué tanto acierta el pronóstico oficial del SMN, por anticipación","description":"Error = pronóstico del SMN − medición oficial del SMN, en temperatura (°C), por capital y por anticipación (horas entre la emisión del pronóstico y la hora pronosticada: 0–24, 24–48, 48–72, 72–120). Cada emisión cuenta por separado. Se publica como indicador con 30 días completos.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":365},"required":false,"name":"dias","in":"query"}],"responses":{"200":{"description":"Error del SMN.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/ciudad/{clave}":{"get":{"tags":["clima"],"operationId":"clima_ciudad","summary":"Ficha de una capital: medición, hoy frente a lo normal, pronóstico oficial y de modelo, Sol, aire, avisos y constancia","description":"Todo lo de una capital en un pedido, cada pieza con su fuente y su papel: la medición oficial vigente del SMN; la máxima y la mínima de hoy (termómetros del observatorio) frente a lo normal (normal oficial del mes y lugar del día en el registro diario del SMN); el pronóstico oficial del SMN por municipio (horas y 4 días); el pronóstico de modelo a 10 días con índice UV (Open-Meteo); amanecer y atardecer calculados; calidad del aire; avisos del SMN vigentes que cubren la capital; la constancia de su observatorio en 7 días y el error del modelo en 30 días con su regla de publicación.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"clave","in":"path"}],"responses":{"200":{"description":"Ficha.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/normales/{clave}":{"get":{"tags":["clima"],"operationId":"clima_normales","summary":"Lo normal de una capital: normal oficial del mes y distribución del día en el registro del SMN","description":"Normal climatológica oficial del observatorio (SMN; 1991-2020 o, si el SMN no la publica, 1981-2010, o ninguna, dicho así) y distribución de la máxima y la mínima diarias del registro diario del mismo observatorio en una ventana de 15 días centrada en la fecha (`fecha` = MM-DD; por omisión, hoy en la capital). Percentiles 0, 5, …, 100. Generado con scripts/clima/generar_normales.py, con huella SHA-256 de cada archivo fuente.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"clave","in":"path"},{"schema":{"type":"string","pattern":"^\\d{2}-\\d{2}$"},"required":false,"name":"fecha","in":"query"}],"responses":{"200":{"description":"Lo normal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/normal-hoy":{"get":{"tags":["clima"],"operationId":"clima_normal_hoy","summary":"Las 32 capitales hoy frente a lo normal","description":"Para cada capital, la máxima y la mínima de hoy (termómetros del observatorio del SMN; «hasta ahora» mientras no llega el mensaje de las 00 UTC) frente a la normal oficial del mes y su percentil en el registro diario del observatorio.","responses":{"200":{"description":"Hoy frente a lo normal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/constancia":{"get":{"tags":["clima"],"operationId":"clima_constancia","summary":"Constancia de los 32 observatorios del SMN: cuántas horas llegaron, cuáles faltan y a qué horas","description":"Por observatorio, en los últimos `dias` (1 a 30, por omisión 7): horas vigiladas, lecturas que llegaron, marcadas y faltantes, racha actual y peor racha sin lectura, faltas por bloque de 6 horas locales, retraso mediano de publicación del SMN y una franja de una letra por hora. Ordenado de menos a más constante.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":30},"required":false,"name":"dias","in":"query"}],"responses":{"200":{"description":"Constancia.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/pronostico-smn/{clave}":{"get":{"tags":["clima"],"operationId":"clima_pronostico_smn","summary":"Pronóstico oficial del SMN para una capital (horas y 4 días)","description":"Servicio Meteorológico Nacional (CONAGUA), Pronóstico por municipios (servicio web): la emisión vigente para el municipio de la capital. Se guardan todas las emisiones para medir su acierto.","parameters":[{"schema":{"type":"string","pattern":"^\\d{2}$"},"required":true,"name":"clave","in":"path"}],"responses":{"200":{"description":"Pronóstico oficial.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/lotes":{"get":{"tags":["clima"],"operationId":"clima_lotes","summary":"Completitud hora por hora: cuántas de las 32 llegaron y cuáles faltan","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":720},"required":false,"name":"horas","in":"query"}],"responses":{"200":{"description":"Lotes.","content":{"application/json":{"schema":{"type":"object","properties":{"esperadas":{"type":"integer"},"lotes":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["esperadas","lotes"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/sonda-emas":{"get":{"tags":["clima"],"operationId":"clima_sonda_emas","summary":"Sonda diaria del portal de estaciones automáticas de CONAGUA","responses":{"200":{"description":"Últimos 60 días.","content":{"application/json":{"schema":{"type":"object","properties":{"dias":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["dias"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/entrega":{"get":{"tags":["clima"],"operationId":"clima_entrega","summary":"Entrega en vivo: conexiones abiertas y latencias medidas","description":"El dato `datos-mexico/clima-entrega` del Protocolo DPM. Latencia de cada entrega = de que la lectura quedó guardada en el observatorio a que el navegador (página visible) confirmó recibirla, medida con relojes del servidor. No es la antigüedad de la medición. Conexión: WebSocket en wss://api.datosmexico.org/api/v1/clima/en-vivo.","responses":{"200":{"description":"Cifras de la entrega.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/entrega/minutos":{"get":{"tags":["clima"],"operationId":"clima_entrega_minutos","summary":"Registro de la entrega en vivo, minuto por minuto (solo lectura)","description":"Un renglón por minuto cerrado hace más de dos minutos con entregas a páginas visibles, confirmaciones de páginas ocultas, la peor latencia del minuto (ms, reloj del servidor) y si ya se reportó al pulso del Protocolo DPM. Sin datos de visitantes. Permite recalcular la entrega desde su registro (auditoría 002, recomendación 1). Hasta 35 días.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":840},"required":false,"name":"horas","in":"query"}],"responses":{"200":{"description":"Minutos.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/comprobacion/estaciones":{"get":{"tags":["clima"],"operationId":"clima_comprobacion_estaciones","summary":"Comprobación de cara pública de la medición oficial para el pulso DPM","responses":{"200":{"description":"Último refresco y refrescos de la última hora.","content":{"application/json":{"schema":{"type":"object","properties":{"ultimo_refresco":{"type":["string","null"]},"refrescos_ultima_hora":{"type":"integer"}},"required":["ultimo_refresco","refrescos_ultima_hora"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/comprobacion/entrega":{"get":{"tags":["clima"],"operationId":"clima_comprobacion_entrega","summary":"Comprobación de cara pública de la entrega en vivo para el pulso DPM","responses":{"200":{"description":"Última entrega y entregas de la última hora.","content":{"application/json":{"schema":{"type":"object","properties":{"ultimo_refresco":{"type":["string","null"]},"refrescos_ultima_hora":{"type":"integer"}},"required":["ultimo_refresco","refrescos_ultima_hora"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/malla/{malla}":{"get":{"tags":["clima"],"operationId":"clima_malla","summary":"Malla de pronóstico para el mapa animado: lluvia, temperatura, viento y nubes, 54 horas","description":"Manifiesto de la corrida vigente del modelo GFS de la NOAA. `mexico`: 0.25°, recortada a México y sus mares (4° a 36° N, 122° a 82° O; 161 × 129 puntos), hora por hora de la 1 a la 54. `mundo`: 1°, el planeta entero (360 × 181 puntos), cada 3 horas de la 3 a la 54. Cada variable es un archivo binario comprimido con un byte por punto y por paso; la codificación de cada uno está en el manifiesto. Es pronóstico de modelo, no medición.","parameters":[{"schema":{"type":"string","enum":["mexico","mundo"]},"required":true,"name":"malla","in":"path"}],"responses":{"200":{"description":"Manifiesto.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"Aún no hay una corrida completa.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/malla/{malla}/{corrida}/{variable}":{"get":{"tags":["clima"],"operationId":"clima_malla_archivo","summary":"Archivo binario de una variable de la malla de pronóstico","parameters":[{"schema":{"type":"string","enum":["mexico","mundo"]},"required":true,"name":"malla","in":"path"},{"schema":{"type":"string","pattern":"^\\d{10}$"},"required":true,"name":"corrida","in":"path"},{"schema":{"type":"string","enum":["lluvia","temperatura","viento","nubes"]},"required":true,"name":"variable","in":"path"}],"responses":{"200":{"description":"Bytes comprimidos (gzip): pasos × capas × puntos de la malla."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/satelite":{"get":{"tags":["clima"],"operationId":"clima_satelite","summary":"Satélite de las últimas tres horas para el mapa animado: un cuadro cada 20 minutos","description":"Manifiesto de los cuadros guardados: GOES-Oeste y GOES-Este en color (GeoColor de la NOAA), pedidos a NASA GIBS una sola vez y guardados por el observatorio. Dos regiones: `mexico` (125° a 75° O, 0° a 37° N) y `america` (180° a 0°, 75° S a 75° N), en Web Mercator con sus esquinas en grados. Es imagen real del satélite, no pronóstico.","responses":{"200":{"description":"Manifiesto.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"Aún no hay cuadros guardados.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/avisos":{"get":{"tags":["clima"],"operationId":"clima_avisos","summary":"Avisos oficiales del SMN vigentes, con sus zonas","description":"Avisos del Servicio Meteorológico Nacional tal como los publica en su canal CAP 1.2 (licencia CC BY 4.0), custodiados por el observatorio cada 5 minutos con su mensaje original y su huella SHA-256. Vigente = no ha vencido y ningún mensaje posterior lo actualiza. Las zonas son los polígonos que dibuja el SMN. `ultimo_por_tipo` dice cuándo publicó el SMN el último aviso de cada tipo en ese canal: si un tipo no aparece desde hace días, el canal no lo está trayendo (desde el 19 de octubre de 2026, los de frente frío solo están en el sitio web del SMN).","responses":{"200":{"description":"Avisos vigentes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/avisos/{sha256}":{"get":{"tags":["clima"],"operationId":"clima_aviso_original","summary":"Mensaje CAP original de un aviso del SMN, tal como se recibió","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"required":true,"name":"sha256","in":"path"}],"responses":{"200":{"description":"XML del mensaje CAP 1.2."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/clima/satelite/{region}/{tiempo}":{"get":{"tags":["clima"],"operationId":"clima_satelite_cuadro","summary":"Imagen JPEG de un cuadro del satélite","parameters":[{"schema":{"type":"string","enum":["rapido","mexico","america"]},"required":true,"name":"region","in":"path"},{"schema":{"type":"string","pattern":"^\\d{12}$"},"required":true,"name":"tiempo","in":"path"}],"responses":{"200":{"description":"JPEG en Web Mercator; sus esquinas están en el manifiesto."},"404":{"description":"No existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/sismos/recientes":{"get":{"tags":["sismos"],"operationId":"sismos_recientes","summary":"Sismos recientes del SSN con la latencia medida de su publicación","description":"Los sismos que el observatorio ha visto en el canal RSS de últimos sismos del SSN (UNAM), leído una vez por minuto, cada uno con el instante de origen según el SSN, el primer instante en que el observatorio lo vio y la latencia entre ambos. Es la sonda del Protocolo DPM para responder, con medida y no con suposición, si México tiene un dato público que llegue en segundos. `limit` 1-500; `desde` ISO opcional.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string"},"required":false,"name":"desde","in":"query"}],"responses":{"200":{"description":"Sismos y resumen de latencias.","content":{"application/json":{"schema":{"type":"object","properties":{"fuente":{"type":"string"},"fuente_url":{"type":"string"},"lecturas":{"type":"object","properties":{"cada_ms":{"type":"integer"},"ultima":{"type":["string","null"]},"ultima_correcta":{"type":["string","null"]}},"required":["cada_ms","ultima","ultima_correcta"]},"latencia":{"type":"object","properties":{"n":{"type":"integer"},"mediana_s":{"type":["number","null"]},"p90_s":{"type":["number","null"]},"maxima_s":{"type":["number","null"]},"desde":{"type":["string","null"]}},"required":["n","mediana_s","p90_s","maxima_s","desde"]},"dpm":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"ficha":{"type":"string"}},"required":["sistema","dato","ficha"]},"sismos":{"type":"array","items":{"type":"object","properties":{"origen_utc":{"type":"string"},"visto_en":{"type":"string"},"latencia_s":{"type":"integer"},"magnitud":{"type":["number","null"]},"lat":{"type":["number","null"]},"lon":{"type":["number","null"]},"profundidad_km":{"type":["number","null"]},"lugar":{"type":"string"},"enlace":{"type":["string","null"]}},"required":["origen_utc","visto_en","latencia_s","magnitud","lat","lon","profundidad_km","lugar","enlace"]}}},"required":["fuente","fuente_url","lecturas","latencia","dpm","sismos"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/sismos/comprobacion":{"get":{"tags":["sismos"],"operationId":"sismos_comprobacion","summary":"Comprobación de cara pública de la sonda de sismos para el pulso DPM","responses":{"200":{"description":"Última lectura y lecturas de la última hora.","content":{"application/json":{"schema":{"type":"object","properties":{"ultimo_refresco":{"type":["string","null"]},"refrescos_ultima_hora":{"type":"integer"}},"required":["ultimo_refresco","refrescos_ultima_hora"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/estado":{"get":{"tags":["dpm"],"operationId":"dpm_estado","summary":"Estado del pulso: sistemas, clases vigentes, caudal y usuarios DPM diarios","description":"La única fuente autorizada de las cifras del Protocolo DPM. Sistemas adheridos con su estado, cada dato con su clase vigente (calculada por reloj al cierre de cada minuto, con cinco minutos de gracia), los dos caudales con su ventana (nunca sumados) y los usuarios DPM diarios del último día completo, sumados por sistema. Solo los sistemas con adhesión verificada aportan a las cifras.","responses":{"200":{"description":"Estado del pulso.","content":{"application/json":{"schema":{"type":"object","properties":{"protocolo":{"type":"object","properties":{"nombre":{"type":"string"},"version":{"type":"string"},"url":{"type":"string"}},"required":["nombre","version","url"]},"calculado_en":{"type":"string"},"instante_evaluado":{"type":["string","null"]},"sistemas":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"nombre":{"type":"string"},"operador":{"type":"string"},"url":{"type":["string","null"]},"estado":{"type":"string","enum":["declarada","verificada"]},"adhesion_declarada":{"type":"string"},"estado_desde":{"type":["string","null"]},"ultimo_reporte":{"type":["string","null"],"description":"Instante en que el pulso recibió el último resumen por minuto de este sistema."},"dias_reportados_7":{"type":"integer","description":"Días civiles (America/Mexico_City) de los últimos siete completos con al menos un resumen puntual; con siete pasa a verificada."},"datos":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"fuente_tipo":{"type":"string","enum":["calendario","evento"]},"via":{"type":"string","enum":["consulta","entrega"]},"modo":{"type":"string","enum":["servido","custodiado"]},"comprobacion":{"type":"object","properties":{"url":{"type":["string","null"]},"ultima":{"type":["object","null"],"properties":{"instante":{"type":"string"},"resultado":{"type":"string","enum":["coincide","no-coincide","sin-respuesta"]},"detalle":{"type":["string","null"]}},"required":["instante","resultado","detalle"]}},"required":["url","ultima"]},"relojes":{"type":"object","properties":{"fuente_ms":{"type":["integer","null"],"description":"Fuente por calendario: periodo de publicación. Fuente por evento: latencia de entrega declarada (el pulso la eleva si observa una mayor)."},"refresco_peor_intervalo_ms":{"type":["integer","null"],"description":"Vía de consulta: peor intervalo entre consultas de la última ventana. Vía de entrega: peor latencia del evento a la persona."},"verificacion":{"type":["string","null"]}},"required":["fuente_ms","refresco_peor_intervalo_ms","verificacion"]},"clase":{"type":"string","enum":["DPMS","DPS","DPM","fuera-de-clase","sin-ventana"]},"clase_desde":{"type":["string","null"]},"ventana":{"type":["object","null"],"properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"vigente":{"type":"boolean"}},"required":["desde","hasta","vigente"],"description":"La hora sobre la que se calculó la clase. Vía de entrega (0.6.0): si en la hora vigente nadie recibió el dato, es la hora más reciente con entregas (sin límite de antigüedad; la clase se sostiene mientras la comprobación de cara pública siga coincidiendo), y `vigente` es falso."},"instante_evaluado":{"type":["string","null"]},"evaluado_en":{"type":["string","null"]},"declarado_en":{"type":"string"}},"required":["sistema","dato","nombre","fuente","fuente_tipo","via","modo","comprobacion","relojes","clase","clase_desde","ventana","instante_evaluado","evaluado_en","declarado_en"]}}},"required":["sistema","nombre","operador","url","estado","adhesion_declarada","estado_desde","ultimo_reporte","dias_reportados_7","datos"]}},"caudal":{"type":"object","properties":{"refresco":{"type":"object","properties":{"observaciones_por_minuto":{"type":["number","null"]},"observaciones":{"type":"integer"},"ventana":{"type":"string"},"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["observaciones_por_minuto","observaciones","ventana","desde","hasta"]},"ingesta":{"type":"object","properties":{"observaciones_por_minuto":{"type":["number","null"]},"observaciones":{"type":"integer"},"ventana":{"type":"string"},"desde":{"type":"string"},"hasta":{"type":"string"}},"required":["observaciones_por_minuto","observaciones","ventana","desde","hasta"]},"nota":{"type":"string"}},"required":["refresco","ingesta","nota"]},"usuarios_dpm_diarios":{"type":"object","properties":{"fecha":{"type":"string"},"total":{"type":["integer","null"]},"por_sistema":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"usuarios_distintos":{"type":"integer"},"metodo":{"type":"string"},"cuenta":{"type":"boolean"},"motivo":{"type":["string","null"]}},"required":["sistema","usuarios_distintos","metodo","cuenta","motivo"]}},"leyenda":{"type":"string"}},"required":["fecha","total","por_sistema","leyenda"]},"regla":{"type":"string"}},"required":["protocolo","calculado_en","instante_evaluado","sistemas","caudal","usuarios_dpm_diarios","regla"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/sistemas/{sistema}":{"get":{"tags":["dpm"],"operationId":"dpm_sistema","summary":"Un sistema adherido: ficha, estado e historial de estados","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"}],"responses":{"200":{"description":"Sistema.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"nombre":{"type":"string"},"operador":{"type":"string"},"url":{"type":["string","null"]},"estado":{"type":"string","enum":["declarada","verificada"]},"adhesion_declarada":{"type":"string"},"estado_desde":{"type":["string","null"]},"ultimo_reporte":{"type":["string","null"],"description":"Instante en que el pulso recibió el último resumen por minuto de este sistema."},"dias_reportados_7":{"type":"integer","description":"Días civiles (America/Mexico_City) de los últimos siete completos con al menos un resumen puntual; con siete pasa a verificada."},"datos":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"fuente_tipo":{"type":"string","enum":["calendario","evento"]},"via":{"type":"string","enum":["consulta","entrega"]},"modo":{"type":"string","enum":["servido","custodiado"]},"comprobacion":{"type":"object","properties":{"url":{"type":["string","null"]},"ultima":{"type":["object","null"],"properties":{"instante":{"type":"string"},"resultado":{"type":"string","enum":["coincide","no-coincide","sin-respuesta"]},"detalle":{"type":["string","null"]}},"required":["instante","resultado","detalle"]}},"required":["url","ultima"]},"relojes":{"type":"object","properties":{"fuente_ms":{"type":["integer","null"],"description":"Fuente por calendario: periodo de publicación. Fuente por evento: latencia de entrega declarada (el pulso la eleva si observa una mayor)."},"refresco_peor_intervalo_ms":{"type":["integer","null"],"description":"Vía de consulta: peor intervalo entre consultas de la última ventana. Vía de entrega: peor latencia del evento a la persona."},"verificacion":{"type":["string","null"]}},"required":["fuente_ms","refresco_peor_intervalo_ms","verificacion"]},"clase":{"type":"string","enum":["DPMS","DPS","DPM","fuera-de-clase","sin-ventana"]},"clase_desde":{"type":["string","null"]},"ventana":{"type":["object","null"],"properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"vigente":{"type":"boolean"}},"required":["desde","hasta","vigente"],"description":"La hora sobre la que se calculó la clase. Vía de entrega (0.6.0): si en la hora vigente nadie recibió el dato, es la hora más reciente con entregas (sin límite de antigüedad; la clase se sostiene mientras la comprobación de cara pública siga coincidiendo), y `vigente` es falso."},"instante_evaluado":{"type":["string","null"]},"evaluado_en":{"type":["string","null"]},"declarado_en":{"type":"string"}},"required":["sistema","dato","nombre","fuente","fuente_tipo","via","modo","comprobacion","relojes","clase","clase_desde","ventana","instante_evaluado","evaluado_en","declarado_en"]}},"historial_estados":{"type":"array","items":{"type":"object","properties":{"desde":{"type":"string"},"estado":{"type":"string","enum":["declarada","verificada"]}},"required":["desde","estado"]}}},"required":["sistema","nombre","operador","url","estado","adhesion_declarada","estado_desde","ultimo_reporte","dias_reportados_7","datos","historial_estados"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/sistemas":{"post":{"tags":["dpm"],"operationId":"dpm_sistema_alta","summary":"Registrar un sistema adherido y emitir su llave de reporte (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Crea el sistema en estado declarada, con la fecha de adhesión de su ficha en el registro, y devuelve la llave de reporte una sola vez: el pulso guarda únicamente su hash.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"nombre":{"type":"string","minLength":1,"maxLength":200},"operador":{"type":"string","minLength":1,"maxLength":200},"url":{"type":["string","null"],"maxLength":300,"format":"uri"},"adhesion_declarada":{"type":"string"}},"required":["sistema","nombre","operador","adhesion_declarada"]}}}},"responses":{"201":{"description":"Sistema registrado; la llave solo se muestra aquí.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"llave":{"type":"string"},"aviso":{"type":"string"}},"required":["sistema","llave","aviso"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"409":{"description":"El sistema ya existe.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/sistemas/{sistema}/llave":{"post":{"tags":["dpm"],"operationId":"dpm_sistema_llave","summary":"Emitir una llave de reporte nueva para un sistema (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Invalida la llave anterior. Úsalo para un sistema sembrado sin llave o para rotarla.","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"}],"responses":{"201":{"description":"Llave nueva; solo se muestra aquí.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"llave":{"type":"string"},"aviso":{"type":"string"}},"required":["sistema","llave","aviso"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/datos/{sistema}/{dato}":{"get":{"tags":["dpm"],"operationId":"dpm_dato","summary":"Un dato: catálogo vigente, clase vigente, peor intervalo y los tres relojes","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"},{"schema":{"type":"string"},"required":true,"name":"dato","in":"path"}],"responses":{"200":{"description":"Dato.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"fuente_tipo":{"type":"string","enum":["calendario","evento"]},"via":{"type":"string","enum":["consulta","entrega"]},"modo":{"type":"string","enum":["servido","custodiado"]},"comprobacion":{"type":"object","properties":{"url":{"type":["string","null"]},"ultima":{"type":["object","null"],"properties":{"instante":{"type":"string"},"resultado":{"type":"string","enum":["coincide","no-coincide","sin-respuesta"]},"detalle":{"type":["string","null"]}},"required":["instante","resultado","detalle"]}},"required":["url","ultima"]},"relojes":{"type":"object","properties":{"fuente_ms":{"type":["integer","null"],"description":"Fuente por calendario: periodo de publicación. Fuente por evento: latencia de entrega declarada (el pulso la eleva si observa una mayor)."},"refresco_peor_intervalo_ms":{"type":["integer","null"],"description":"Vía de consulta: peor intervalo entre consultas de la última ventana. Vía de entrega: peor latencia del evento a la persona."},"verificacion":{"type":["string","null"]}},"required":["fuente_ms","refresco_peor_intervalo_ms","verificacion"]},"clase":{"type":"string","enum":["DPMS","DPS","DPM","fuera-de-clase","sin-ventana"]},"clase_desde":{"type":["string","null"]},"ventana":{"type":["object","null"],"properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"vigente":{"type":"boolean"}},"required":["desde","hasta","vigente"],"description":"La hora sobre la que se calculó la clase. Vía de entrega (0.6.0): si en la hora vigente nadie recibió el dato, es la hora más reciente con entregas (sin límite de antigüedad; la clase se sostiene mientras la comprobación de cara pública siga coincidiendo), y `vigente` es falso."},"instante_evaluado":{"type":["string","null"]},"evaluado_en":{"type":["string","null"]},"declarado_en":{"type":"string"}},"required":["sistema","dato","nombre","fuente","fuente_tipo","via","modo","comprobacion","relojes","clase","clase_desde","ventana","instante_evaluado","evaluado_en","declarado_en"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"put":{"tags":["dpm"],"operationId":"dpm_dato_declarar","summary":"Declarar o actualizar un dato en el catálogo (llave del sistema)","security":[{"LlaveDPM":[]}],"description":"§3. `fuente_tipo` `calendario` (por omisión): `reloj_fuente_ms` es la cota, el periodo con el que la fuente publica; `null` deja al dato fuera de clase. `fuente_tipo` `evento`: `latencia_fuente_ms` es la latencia de entrega declarada del evento al sistema, cota cuando la ventana no tiene eventos; el pulso la eleva si observa una mayor y una redeclaración no puede bajarla por debajo de la peor observada en los últimos siete días; `null` deja al dato fuera de clase. `via` `consulta` (por omisión) o `entrega` (protocolo 0.3 §6). `url_comprobacion` (0.4 §8 bis): dirección pública https que responde `{ultimo_refresco, refrescos_ultima_hora}`; sin ella el dato no puede estar en clase. `ultima_verificacion` es el reloj de la verificación; sin él, un dato custodiado no cuenta en el caudal. Cada versión queda en el historial del dato.","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"},{"schema":{"type":"string"},"required":true,"name":"dato","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string","minLength":1,"maxLength":200},"fuente":{"type":"string","minLength":1,"maxLength":200},"fuente_tipo":{"type":"string","enum":["calendario","evento"],"default":"calendario"},"reloj_fuente_ms":{"type":["integer","null"],"minimum":0},"latencia_fuente_ms":{"type":["integer","null"],"minimum":0},"via":{"type":"string","enum":["consulta","entrega"],"default":"consulta"},"url_comprobacion":{"type":["string","null"],"maxLength":500,"pattern":"^https:\\/\\/"},"modo":{"type":"string","enum":["servido","custodiado"]},"ultima_verificacion":{"type":["string","null"]}},"required":["nombre","fuente","modo"]}}}},"responses":{"200":{"description":"Dato declarado.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"fuente_tipo":{"type":"string","enum":["calendario","evento"]},"via":{"type":"string","enum":["consulta","entrega"]},"modo":{"type":"string","enum":["servido","custodiado"]},"comprobacion":{"type":"object","properties":{"url":{"type":["string","null"]},"ultima":{"type":["object","null"],"properties":{"instante":{"type":"string"},"resultado":{"type":"string","enum":["coincide","no-coincide","sin-respuesta"]},"detalle":{"type":["string","null"]}},"required":["instante","resultado","detalle"]}},"required":["url","ultima"]},"relojes":{"type":"object","properties":{"fuente_ms":{"type":["integer","null"],"description":"Fuente por calendario: periodo de publicación. Fuente por evento: latencia de entrega declarada (el pulso la eleva si observa una mayor)."},"refresco_peor_intervalo_ms":{"type":["integer","null"],"description":"Vía de consulta: peor intervalo entre consultas de la última ventana. Vía de entrega: peor latencia del evento a la persona."},"verificacion":{"type":["string","null"]}},"required":["fuente_ms","refresco_peor_intervalo_ms","verificacion"]},"clase":{"type":"string","enum":["DPMS","DPS","DPM","fuera-de-clase","sin-ventana"]},"clase_desde":{"type":["string","null"]},"ventana":{"type":["object","null"],"properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"vigente":{"type":"boolean"}},"required":["desde","hasta","vigente"],"description":"La hora sobre la que se calculó la clase. Vía de entrega (0.6.0): si en la hora vigente nadie recibió el dato, es la hora más reciente con entregas (sin límite de antigüedad; la clase se sostiene mientras la comprobación de cara pública siga coincidiendo), y `vigente` es falso."},"instante_evaluado":{"type":["string","null"]},"evaluado_en":{"type":["string","null"]},"declarado_en":{"type":"string"}},"required":["sistema","dato","nombre","fuente","fuente_tipo","via","modo","comprobacion","relojes","clase","clase_desde","ventana","instante_evaluado","evaluado_en","declarado_en"]}}}},"401":{"description":"Llave de reporte ausente o que no corresponde al sistema.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/datos/{sistema}/{dato}/historial":{"get":{"tags":["dpm"],"operationId":"dpm_dato_historial","summary":"Historial de clases de un dato (no se edita) y versiones de su catálogo","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"},{"schema":{"type":"string"},"required":true,"name":"dato","in":"path"}],"responses":{"200":{"description":"Historial.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"clases":{"type":"array","items":{"type":"object","properties":{"desde":{"type":"string"},"clase":{"type":"string","enum":["DPMS","DPS","DPM","fuera-de-clase","sin-ventana"]},"w_ms":{"type":["integer","null"]},"ventana_hasta":{"type":["string","null"]}},"required":["desde","clase","w_ms","ventana_hasta"]}},"catalogo":{"type":"array","items":{"type":"object","properties":{"desde":{"type":"string"},"nombre":{"type":"string"},"fuente":{"type":"string"},"reloj_fuente_ms":{"type":["integer","null"]},"fuente_tipo":{"type":"string","enum":["calendario","evento"]},"latencia_fuente_ms":{"type":["integer","null"]},"via":{"type":"string","enum":["consulta","entrega"]},"modo":{"type":"string","enum":["servido","custodiado"]},"ultima_verificacion":{"type":["string","null"]},"nota":{"type":["string","null"]}},"required":["desde","nombre","fuente","reloj_fuente_ms","fuente_tipo","latencia_fuente_ms","via","modo","ultima_verificacion","nota"]}}},"required":["sistema","dato","clases","catalogo"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/datos/{sistema}/{dato}/comprobaciones":{"get":{"tags":["dpm"],"operationId":"dpm_dato_comprobaciones","summary":"Historial de comprobaciones de cara pública de un dato (§7 bis)","description":"Cada diez minutos el pulso consulta por su cuenta la dirección pública de comprobación del dato y compara con lo reportado: último refresco a ±5 minutos y refrescos de la última hora a ±20 %. Tres resultados seguidos distintos de «coincide» sacan al dato de clase. Un dato sin dirección no puede estar en clase.","parameters":[{"schema":{"type":"string"},"required":true,"name":"sistema","in":"path"},{"schema":{"type":"string"},"required":true,"name":"dato","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Comprobaciones, de la más reciente a la más antigua.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"url_comprobacion":{"type":["string","null"]},"comprobaciones":{"type":"array","items":{"type":"object","properties":{"instante":{"type":"string"},"resultado":{"type":"string","enum":["coincide","no-coincide","sin-respuesta"]},"ultimo_refresco_visto":{"type":["string","null"]},"refrescos_hora_vistos":{"type":["integer","null"]},"ultimo_reportado":{"type":["string","null"]},"refrescos_hora_reportados":{"type":["integer","null"]},"detalle":{"type":["string","null"]}},"required":["instante","resultado","ultimo_refresco_visto","refrescos_hora_vistos","ultimo_reportado","refrescos_hora_reportados","detalle"]}}},"required":["sistema","dato","url_comprobacion","comprobaciones"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/resumenes":{"post":{"tags":["dpm"],"operationId":"dpm_resumenes","summary":"Reportar resúmenes por minuto (llave del sistema)","security":[{"LlaveDPM":[]}],"description":"§4. Por cada dato y minuto: refrescos ocurridos, instante del primero y del último, peor intervalo dentro del minuto y observaciones nuevas. Fuentes por evento: `eventos` y `latencia_fuente_max_ms` (obligatoria si hubo eventos). Vía de entrega: `entregas` y `latencia_entrega_max_ms` (obligatoria si hubo entregas); con entregas, `refrescos` puede ser 0 y entonces `primero` y `ultimo` son la primera y la última entrega. Un minuto sin refrescos ni entregas no se reporta. Hasta 1,000 resúmenes por envío. Un resumen es puntual si llega dentro de los cinco minutos posteriores al fin de su minuto; solo los puntuales cuentan para la clase. Se aceptan hasta 24 horas tarde para historial y caudal; después, 422. Reenviar la misma clave reemplaza el resumen sin recuperar la puntualidad perdida.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"resumenes":{"type":"array","items":{"type":"object","properties":{"dato":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"minuto":{"type":"string"},"refrescos":{"type":"integer","minimum":0},"primero":{"type":"string"},"ultimo":{"type":"string"},"intervalo_max_ms":{"type":"integer","minimum":0},"observaciones":{"type":"integer","minimum":0},"eventos":{"type":"integer","minimum":0},"latencia_fuente_max_ms":{"type":"integer","minimum":0},"entregas":{"type":"integer","minimum":0},"latencia_entrega_max_ms":{"type":"integer","minimum":0}},"required":["dato","minuto","refrescos","primero","ultimo","intervalo_max_ms","observaciones"]},"minItems":1,"maxItems":1000}},"required":["sistema","resumenes"]}}}},"responses":{"200":{"description":"Resúmenes recibidos.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"recibidos":{"type":"integer"},"puntuales":{"type":"integer"},"tardios":{"type":"integer"},"recibido":{"type":"string"}},"required":["sistema","recibidos","puntuales","tardios","recibido"]}}}},"401":{"description":"Llave de reporte ausente o que no corresponde al sistema.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"413":{"description":"Más de 1,000 resúmenes en un envío.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/ingestas":{"post":{"tags":["dpm"],"operationId":"dpm_ingestas","summary":"Reportar una ingesta de universo completo (llave del sistema)","security":[{"LlaveDPM":[]}],"description":"§5. Las cargas de universos no pasan por el resumen por minuto: alimentan el caudal de ingesta, separado del de refresco. Sin `verificacion` la ingesta se guarda pero no cuenta en el caudal. El dato debe ser custodiado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"dato":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"inicio":{"type":"string"},"fin":{"type":"string"},"observaciones":{"type":"integer","minimum":0},"verificacion":{"type":"object","properties":{"metodo":{"type":"string","minLength":1,"maxLength":300},"resultado":{"type":"string","minLength":1,"maxLength":300}},"required":["metodo","resultado"]}},"required":["sistema","dato","inicio","fin","observaciones"]}}}},"responses":{"201":{"description":"Ingesta registrada.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"dato":{"type":"string"},"inicio":{"type":"string"},"fin":{"type":"string"},"observaciones":{"type":"integer"},"cuenta_en_caudal":{"type":"boolean"},"recibido":{"type":"string"}},"required":["sistema","dato","inicio","fin","observaciones","cuenta_en_caudal","recibido"]}}}},"401":{"description":"Llave de reporte ausente o que no corresponde al sistema.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/usuarios":{"get":{"tags":["dpm"],"operationId":"dpm_usuarios","summary":"Usuarios DPM diarios por fecha y por sistema","description":"Reportes de usuarios distintos por día (America/Mexico_City) con su método de conteo. `desde` y `hasta` en AAAA-MM-DD; por omisión, los últimos 30 días completos. La columna `cuenta` dice si ese reporte entra en la cifra pública (sistema verificado con al menos un dato en clase ese día).","parameters":[{"schema":{"type":"string"},"required":false,"name":"desde","in":"query"},{"schema":{"type":"string"},"required":false,"name":"hasta","in":"query"}],"responses":{"200":{"description":"Usuarios por día.","content":{"application/json":{"schema":{"type":"object","properties":{"desde":{"type":"string"},"hasta":{"type":"string"},"dias":{"type":"array","items":{"type":"object","properties":{"fecha":{"type":"string"},"total":{"type":"integer"},"por_sistema":{"type":"array","items":{"type":"object","properties":{"sistema":{"type":"string"},"usuarios_distintos":{"type":"integer"},"metodo":{"type":"string"},"cuenta":{"type":"boolean"}},"required":["sistema","usuarios_distintos","metodo","cuenta"]}}},"required":["fecha","total","por_sistema"]}},"leyenda":{"type":"string"}},"required":["desde","hasta","dias","leyenda"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"post":{"tags":["dpm"],"operationId":"dpm_usuarios_reporte","summary":"Reportar usuarios distintos de un día (llave del sistema)","security":[{"LlaveDPM":[]}],"description":"§6. Un conteo por sistema y día civil (America/Mexico_City): personas distintas que recibieron al menos un dato de los listados. Nunca identificadores. Un segundo reporte de la misma fecha la reemplaza si llega dentro de los siete días siguientes; después se rechaza. No se aceptan fechas futuras ni el día en curso.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"fecha":{"type":"string"},"usuarios_distintos":{"type":"integer","minimum":0},"metodo":{"type":"string","minLength":1,"maxLength":200},"datos":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,62}$"},"minItems":1,"maxItems":100}},"required":["sistema","fecha","usuarios_distintos","metodo","datos"]}}}},"responses":{"201":{"description":"Reporte registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"sistema":{"type":"string"},"fecha":{"type":"string"},"usuarios_distintos":{"type":"integer"},"metodo":{"type":"string"},"datos":{"type":"array","items":{"type":"string"}},"recibido":{"type":"string"}},"required":["sistema","fecha","usuarios_distintos","metodo","datos","recibido"]}}}},"401":{"description":"Llave de reporte ausente o que no corresponde al sistema.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/insignia/{archivo}":{"get":{"tags":["dpm"],"operationId":"dpm_insignia","summary":"La insignia viva de un sistema (SVG)","description":"`/dpm/v1/insignia/{sistema}.svg`. Muestra el estado de adhesión y, si el sistema está verificado y tiene datos en clase, la clase más fina vigente. Cambia sola en el minuto siguiente a cada evaluación.","parameters":[{"schema":{"type":"string","description":"<sistema>.svg"},"required":true,"description":"<sistema>.svg","name":"archivo","in":"path"}],"responses":{"200":{"description":"SVG de la insignia.","content":{"image/svg+xml":{"schema":{"type":"string"}}}},"404":{"description":"Sistema o dato no registrado.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/dpm/v1/admin/evaluar":{"post":{"tags":["dpm"],"operationId":"dpm_evaluar","summary":"Correr ahora la evaluación de clases y estados (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"La misma evaluación que corre el disparador programado cada minuto (clases al cierre de T = ahora − 5 min) y cada hora (estados). Sirve para operar y para verificar; no cambia las reglas.","responses":{"200":{"description":"Resultado de la evaluación.","content":{"application/json":{"schema":{"type":"object","properties":{"comprobacion":{"type":"object","properties":{"comprobados":{"type":"integer"},"coinciden":{"type":"integer"}},"required":["comprobados","coinciden"]},"clases":{"type":"object","properties":{"instante_evaluado":{"type":"string"},"evaluados":{"type":"integer"},"cambios":{"type":"integer"}},"required":["instante_evaluado","evaluados","cambios"]},"estados":{"type":"object","properties":{"sistemas":{"type":"integer"},"cambios":{"type":"integer"}},"required":["sistemas","cambios"]}},"required":["comprobacion","clases","estados"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/erratas":{"get":{"tags":["erratas"],"operationId":"erratas_lista","summary":"Erratas y observaciones reportadas sobre los datos oficiales","description":"Lista pública de reportes: qué base y registro se cuestiona, qué valor se observó y cuál se propone, quién lo reportó y en qué estado está (pendiente, aceptada, rechazada) con la nota de revisión. Las tablas oficiales nunca cambian por esta vía: una errata aceptada se documenta y se aplica en la siguiente edición cargada. Filtros: `dataset`, `estado`; paginado con `limit` (1-500) y `offset`.","parameters":[{"schema":{"type":"string"},"required":false,"name":"dataset","in":"query"},{"schema":{"type":"string","enum":["pendiente","aceptada","rechazada"]},"required":false,"name":"estado","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"integer","minimum":0,"default":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Erratas.","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"dataset":{"type":"string"},"tabla":{"type":["string","null"]},"registro":{"type":["string","null"]},"campo":{"type":["string","null"]},"valor_observado":{"type":["string","null"]},"valor_propuesto":{"type":["string","null"]},"fuente":{"type":["string","null"]},"comentario":{"type":"string"},"estado":{"type":"string","enum":["pendiente","aceptada","rechazada"]},"nota_revision":{"type":["string","null"]},"reportado_por":{"type":"string"},"revisado_por":{"type":["string","null"]},"creado_en":{"type":"string"},"revisado_en":{"type":["string","null"]}},"required":["id","dataset","tabla","registro","campo","valor_observado","valor_propuesto","fuente","comentario","estado","nota_revision","reportado_por","revisado_por","creado_en","revisado_en"]}}},"required":["total","limit","offset","items"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"post":{"tags":["erratas"],"operationId":"errata_reportar","summary":"Reportar un posible error en un dato oficial (requiere login)","security":[{"OAuth2PasswordBearer":[]}],"description":"Crea un reporte en estado `pendiente`. `dataset` debe ser una clave del catálogo (`/api/v1/catalogo/datasets`); `tabla`, `registro` (llave o id) y `campo` ubican el dato; `valor_observado` y `valor_propuesto` documentan la discrepancia; `fuente` es la publicación oficial que la respalda. Se guarda con el usuario del JWT y la fecha. No modifica ningún dato publicado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dataset":{"type":"string","minLength":1,"maxLength":40},"tabla":{"type":"string","maxLength":80},"registro":{"type":"string","maxLength":200},"campo":{"type":"string","maxLength":80},"valor_observado":{"type":"string","maxLength":500},"valor_propuesto":{"type":"string","maxLength":500},"fuente":{"type":"string","maxLength":500},"comentario":{"type":"string","minLength":10,"maxLength":2000}},"required":["dataset","comentario"]}}}},"responses":{"201":{"description":"Errata registrada.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"dataset":{"type":"string"},"tabla":{"type":["string","null"]},"registro":{"type":["string","null"]},"campo":{"type":["string","null"]},"valor_observado":{"type":["string","null"]},"valor_propuesto":{"type":["string","null"]},"fuente":{"type":["string","null"]},"comentario":{"type":"string"},"estado":{"type":"string","enum":["pendiente","aceptada","rechazada"]},"nota_revision":{"type":["string","null"]},"reportado_por":{"type":"string"},"revisado_por":{"type":["string","null"]},"creado_en":{"type":"string"},"revisado_en":{"type":["string","null"]}},"required":["id","dataset","tabla","registro","campo","valor_observado","valor_propuesto","fuente","comentario","estado","nota_revision","reportado_por","revisado_por","creado_en","revisado_en"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/erratas/{id}":{"get":{"tags":["erratas"],"operationId":"errata_detalle","summary":"Una errata por su id","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Errata.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"dataset":{"type":"string"},"tabla":{"type":["string","null"]},"registro":{"type":["string","null"]},"campo":{"type":["string","null"]},"valor_observado":{"type":["string","null"]},"valor_propuesto":{"type":["string","null"]},"fuente":{"type":["string","null"]},"comentario":{"type":"string"},"estado":{"type":"string","enum":["pendiente","aceptada","rechazada"]},"nota_revision":{"type":["string","null"]},"reportado_por":{"type":"string"},"revisado_por":{"type":["string","null"]},"creado_en":{"type":"string"},"revisado_en":{"type":["string","null"]}},"required":["id","dataset","tabla","registro","campo","valor_observado","valor_propuesto","fuente","comentario","estado","nota_revision","reportado_por","revisado_por","creado_en","revisado_en"]}}}},"404":{"description":"Errata inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"put":{"tags":["erratas"],"operationId":"errata_revisar","summary":"Revisar una errata: aceptarla o rechazarla (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Cambia el estado y registra la nota de revisión, el revisor y la fecha. Aceptar una errata no altera el dato publicado: obliga a documentarla y a corregirla en la siguiente edición cargada, con su verificación. Requiere JWT admin.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"estado":{"type":"string","enum":["aceptada","rechazada","pendiente"]},"nota_revision":{"type":"string","minLength":5,"maxLength":2000}},"required":["estado","nota_revision"]}}}},"responses":{"200":{"description":"Errata revisada.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"dataset":{"type":"string"},"tabla":{"type":["string","null"]},"registro":{"type":["string","null"]},"campo":{"type":["string","null"]},"valor_observado":{"type":["string","null"]},"valor_propuesto":{"type":["string","null"]},"fuente":{"type":["string","null"]},"comentario":{"type":"string"},"estado":{"type":"string","enum":["pendiente","aceptada","rechazada"]},"nota_revision":{"type":["string","null"]},"reportado_por":{"type":"string"},"revisado_por":{"type":["string","null"]},"creado_en":{"type":"string"},"revisado_en":{"type":["string","null"]}},"required":["id","dataset","tabla","registro","campo","valor_observado","valor_propuesto","fuente","comentario","estado","nota_revision","reportado_por","revisado_por","creado_en","revisado_en"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Errata inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"delete":{"tags":["erratas"],"operationId":"errata_borrar","summary":"Retirar un reporte (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Elimina un reporte (por ejemplo, duplicado o sin contenido). Requiere JWT admin. Devuelve 204 sin cuerpo.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"Errata eliminada (sin body)."},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Errata inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/auth/register":{"post":{"tags":["auth"],"operationId":"register_api_v1_auth_register_post","summary":"Registro de usuarios — deshabilitado","description":"Endpoint de registro de usuarios **intencionalmente deshabilitado**. La route existe en el código y siempre devuelve `403 Forbidden` con el mensaje correspondiente. Si en el futuro el observatorio decide abrir registro público, la route ya está lista en el contrato del API y sólo requiere reemplazar el cuerpo de la función por la lógica de creación. La provisión de cuentas admin se hace con `scripts/plataforma_usuario.py` (hash bcrypt directo a la D1 de plataforma); contacto: `df.avila.diaz@gmail.com`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["username","email","password"]}}}},"responses":{"403":{"description":"Registro deshabilitado actualmente. La route existe en el código pero está intencionalmente bloqueada.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}}}}},"/api/v1/auth/token":{"post":{"tags":["auth"],"operationId":"login_api_v1_auth_token_post","summary":"Obtener JWT por OAuth2 password flow","description":"Autenticación por OAuth2 password flow. Recibe `username` y `password` como `application/x-www-form-urlencoded` y devuelve un JWT bearer con vigencia de 30 minutos. El token debe enviarse en endpoints autenticados como `Authorization: Bearer <token>`. Algoritmo de firma: `HS256` (simétrico, secreto en la variable `SECRET_KEY` del worker). Las contraseñas se verifican con bcrypt contra los mismos hashes migrados del legacy.","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","pattern":"^password$"},"username":{"type":"string"},"password":{"type":"string"},"scope":{"type":"string","default":""},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["username","password"]}}}},"responses":{"200":{"description":"Token JWT bearer emitido. Vigencia: 30 minutos.","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string"}},"required":["access_token","token_type"]}}}},"401":{"description":"Credenciales incorrectas (usuario inexistente o password no coincide).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}}}}},"/api/v1/auth/me":{"get":{"tags":["auth"],"operationId":"get_me_api_v1_auth_me_get","summary":"Perfil del usuario autenticado","security":[{"OAuth2PasswordBearer":[]}],"description":"Devuelve el perfil del usuario asociado al JWT enviado en el header `Authorization`. Útil para que un cliente confirme la vigencia del token y obtenga su flag `is_admin`. No incluye el `hashed_password` ni datos sensibles.","responses":{"200":{"description":"Perfil del usuario autenticado.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"username":{"type":"string"},"email":{"type":"string"},"is_active":{"type":"boolean"},"is_admin":{"type":"boolean"},"created_at":{"type":"string"}},"required":["id","username","email","is_active","is_admin","created_at"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/admin/refresh-materialized-views":{"post":{"tags":["admin"],"operationId":"refresh_materialized_views_api_v1_admin_refresh_materialized_views_post","summary":"[Operacional] Recalcular las 5 tablas derivadas del tablero (mv_dashboard_*)","security":[{"OAuth2PasswordBearer":[]}],"description":"**Operacional — no debe consumirse desde producción de forma programática.** Recalcula las cinco tablas derivadas del tablero de servidores públicos de la CDMX (`mv_dashboard_overview`, `mv_dashboard_sectors`, `mv_dashboard_top_positions`, `mv_dashboard_salary_by_age`, `mv_dashboard_seniority`) a partir de las tablas oficiales `personas`, `nombramientos` y catálogos, con las mismas definiciones que las vistas materializadas del legacy. No modifica ningún dato publicado. Diseñado para invocación manual tras cargar una nueva edición del padrón. Rate limit estricto (5/min/IP). Requiere JWT admin.","responses":{"200":{"description":"Refresco completado.","content":{"application/json":{"schema":{"type":"object","properties":{"refreshed":{"type":"array","items":{"type":"string"}},"duration_ms":{"type":"integer"}},"required":["refreshed","duration_ms"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (5 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/admin/espejo":{"post":{"tags":["admin"],"operationId":"admin_espejo_fuente","summary":"[Operacional] Copiar un archivo público del INEGI al almacén (R2) desde la red de Cloudflare","security":[{"OAuth2PasswordBearer":[]}],"description":"Descarga la URL (solo www.inegi.org.mx) y la guarda tal cual en R2 bajo la clave dada (prefijos inegi/fuentes/ o inegi/tabulados/), devolviendo tamaño, ETag y si ya existía con el mismo tamaño. Es la vía para acelerar la ingesta cuando el INEGI limita la velocidad por dirección IP. Requiere JWT admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"clave":{"type":"string","pattern":"^inegi\\/(fuentes|tabulados)\\/[A-Za-z0-9_\\-./()]+$"}},"required":["url","clave"]}}}},"responses":{"200":{"description":"Archivo en R2.","content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string"},"bytes":{"type":"integer"},"etag":{"type":"string"},"existia":{"type":"boolean"},"ms":{"type":"integer"}},"required":["clave","bytes","etag","existia","ms"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"URL o clave inválidas.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{}}}}}},"502":{"description":"El INEGI no entregó el archivo.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/demo/estudiantes":{"get":{"tags":["demo"],"operationId":"list_estudiantes_api_v1_demo_estudiantes_get","summary":"Lista del curso ITAM Bases de Datos sección 001","description":"Retorna las 12 personas del curso (1 profesor + 4 equipo + 7 estudiantes) con sueldo diario, tipo, y estado actual de `reclamar_bono`. Lectura pública sin auth. Orden: profesor → equipo (por sueldo desc) → estudiantes (por sueldo desc).","responses":{"200":{"description":"Lista completa con los 12 registros.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"estudiantes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nombre_completo":{"type":"string"},"rol":{"type":"string","enum":["estudiante","profesor"]},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"]},"seccion":{"type":"string"},"sueldo_diario_mxn":{"type":"string"},"reclamar_bono":{"type":"boolean"},"fecha_creacion":{"type":"string"},"fecha_actualizacion":{"type":"string"}},"required":["id","nombre_completo","rol","tipo","seccion","sueldo_diario_mxn","reclamar_bono","fecha_creacion","fecha_actualizacion"]}},"seccion":{"type":"string"},"fuente":{"type":"string"}},"required":["count","estudiantes","seccion","fuente"]}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/demo/resumen":{"get":{"tags":["demo"],"operationId":"get_resumen_api_v1_demo_resumen_get","summary":"Agregados para la KPI bar del dashboard /demo","description":"Totales en una sola llamada: empleados, bonos reclamados, monto distribuido (N × $50,000 MXN), monto disponible (resto del pool), monto total posible (12 × $50,000 = $600,000 MXN), y nómina diaria total.","responses":{"200":{"description":"Agregados del curso.","content":{"application/json":{"schema":{"type":"object","properties":{"total_empleados":{"type":"integer"},"bonos_reclamados":{"type":"integer"},"bono_unitario_mxn":{"type":"integer"},"monto_distribuido_mxn":{"type":"integer"},"monto_disponible_mxn":{"type":"integer"},"monto_total_posible_mxn":{"type":"integer"},"nomina_diaria_total_mxn":{"type":"string"},"fecha":{"type":"string"}},"required":["total_empleados","bonos_reclamados","bono_unitario_mxn","monto_distribuido_mxn","monto_disponible_mxn","monto_total_posible_mxn","nomina_diaria_total_mxn","fecha"]}}}},"429":{"description":"Rate limit excedido (60 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/demo/estudiantes/{id}":{"get":{"tags":["demo"],"operationId":"get_estudiante_api_v1_demo_estudiantes__id__get","summary":"Detalle de una persona del curso","description":"Devuelve los campos completos (`nombre_completo`, `rol`, `tipo`, `seccion`, `sueldo_diario_mxn`, `reclamar_bono`, fechas) de una persona del curso por su `id`. Lectura pública sin auth.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Detalle del registro.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre_completo":{"type":"string"},"rol":{"type":"string","enum":["estudiante","profesor"]},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"]},"seccion":{"type":"string"},"sueldo_diario_mxn":{"type":"string"},"reclamar_bono":{"type":"boolean"},"fecha_creacion":{"type":"string"},"fecha_actualizacion":{"type":"string"}},"required":["id","nombre_completo","rol","tipo","seccion","sueldo_diario_mxn","reclamar_bono","fecha_creacion","fecha_actualizacion"]}}}},"404":{"description":"Registro inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (120 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/demo/estudiantes/{id}/toggle-bono":{"put":{"tags":["demo"],"operationId":"toggle_bono_api_v1_demo_estudiantes__id__toggle_bono_put","summary":"Toggle del campo reclamar_bono (requiere login)","security":[{"OAuth2PasswordBearer":[]}],"description":"Invierte `reclamar_bono` del registro y actualiza `fecha_actualizacion`. Requiere JWT de cualquier usuario activo (no hace falta admin): durante el checkpoint en vivo la cuenta `DemoAbril` se comparte entre estudiantes y profesor. Devuelve `actor_username` con el usuario del JWT.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Registro actualizado.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre_completo":{"type":"string"},"reclamar_bono":{"type":"boolean"},"fecha_actualizacion":{"type":"string"},"actor_username":{"type":"string"}},"required":["id","nombre_completo","reclamar_bono","fecha_actualizacion","actor_username"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Registro inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (30 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/admin/demo/estudiantes":{"post":{"tags":["demo-admin"],"operationId":"crear_estudiante_api_v1_admin_demo_estudiantes_post","summary":"Crear un nuevo registro en demo.curso_bd (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Inserta una persona en la tabla del curso. `seccion` hereda 'BASES DE DATOS - 001' si se omite; `sueldo_diario_mxn` ≥ 0 con dos decimales. Requiere JWT admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nombre_completo":{"type":"string","minLength":2,"maxLength":120},"rol":{"type":"string","enum":["estudiante","profesor"],"default":"estudiante"},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"],"default":"estudiante"},"seccion":{"type":["string","null"],"maxLength":40},"sueldo_diario_mxn":{"type":"number","minimum":0,"default":0}},"required":["nombre_completo"]}}}},"responses":{"201":{"description":"Registro creado.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre_completo":{"type":"string"},"rol":{"type":"string","enum":["estudiante","profesor"]},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"]},"seccion":{"type":"string"},"sueldo_diario_mxn":{"type":"string"},"reclamar_bono":{"type":"boolean"},"fecha_creacion":{"type":"string"},"fecha_actualizacion":{"type":"string"}},"required":["id","nombre_completo","rol","tipo","seccion","sueldo_diario_mxn","reclamar_bono","fecha_creacion","fecha_actualizacion"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"409":{"description":"Ya existe un registro con ese nombre completo.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/admin/demo/estudiantes/{id}":{"put":{"tags":["demo-admin"],"operationId":"editar_estudiante_api_v1_admin_demo_estudiantes__id__put","summary":"Editar campos de un registro (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Actualiza solo los campos enviados (nombre, rol, tipo, sección, sueldo, reclamar_bono) y `fecha_actualizacion`. Requiere JWT admin.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nombre_completo":{"type":"string","minLength":2,"maxLength":120},"rol":{"type":"string","enum":["estudiante","profesor"]},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"]},"seccion":{"type":"string","maxLength":40},"sueldo_diario_mxn":{"type":"number","minimum":0},"reclamar_bono":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Registro actualizado.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"nombre_completo":{"type":"string"},"rol":{"type":"string","enum":["estudiante","profesor"]},"tipo":{"type":"string","enum":["profesor","equipo","estudiante"]},"seccion":{"type":"string"},"sueldo_diario_mxn":{"type":"string"},"reclamar_bono":{"type":"boolean"},"fecha_creacion":{"type":"string"},"fecha_actualizacion":{"type":"string"}},"required":["id","nombre_completo","rol","tipo","seccion","sueldo_diario_mxn","reclamar_bono","fecha_creacion","fecha_actualizacion"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Registro inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}},"delete":{"tags":["demo-admin"],"operationId":"borrar_estudiante_api_v1_admin_demo_estudiantes__id__delete","summary":"Borrar un registro (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Elimina un registro de la tabla del curso. Requiere JWT admin.","parameters":[{"schema":{"type":"integer"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Registro eliminado.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"deleted":{"type":"boolean"}},"required":["id","deleted"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"404":{"description":"Registro inexistente.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}},"msg":{"type":"string"},"input":{}},"required":["type","loc","msg"]}}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}},"/api/v1/admin/demo/reset":{"post":{"tags":["demo-admin"],"operationId":"reset_bonos_api_v1_admin_demo_reset_post","summary":"Resetear todos los reclamar_bono a FALSE (admin)","security":[{"OAuth2PasswordBearer":[]}],"description":"Pone `reclamar_bono` en falso en todos los registros que lo tenían en verdadero y devuelve cuántos cambió. Requiere JWT admin.","responses":{"200":{"description":"Reinicio hecho.","content":{"application/json":{"schema":{"type":"object","properties":{"filas_reseteadas":{"type":"integer"},"fecha":{"type":"string"}},"required":["filas_reseteadas","fecha"]}}}},"401":{"description":"JWT ausente o inválido.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"403":{"description":"Usuario autenticado sin privilegios admin.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}},"429":{"description":"Rate limit excedido (20 req/min por IP).","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string"}},"required":["detail"]}}}}}}}},"webhooks":{}}