{"openapi":"3.1.0","info":{"title":"Valida API","version":"1.3.0","summary":"Validacion SARLAFT contra listas vinculantes y de referencia, con contador de paquete y alertas por API","description":"\nAPI de **Valida**, producto de MeTRIK SAS para validar personas naturales y juridicas contra listas\nSARLAFT. Servidor a servidor: la API key nunca debe vivir en un navegador ni en una app movil.\n\nGuia completa para integradores (quickstart, idempotencia, consumo, cobro, webhooks, concurrencia,\nejemplos en curl, JavaScript y Python): **https://app.valida.metrikone.co/docs**\n\n## Listas y tiers\n\n| Tier | Listas | Que significa |\n|---|---|---|\n| `1_vinculante` | ONU Consolidated, CSN Colombia | Obligacion legal explicita en Colombia |\n| `2_obligatoria` | PEP Colombia (SIGEP) | Obligatoria de construir por el sujeto obligado |\n| `3_referencia` | OFAC SDN, UE Consolidated | **No vinculantes** en Colombia; estandar de facto de debida diligencia |\n\nCada respuesta declara contra que version de cada lista se comparo (`listas_consultadas` y header\n`X-Valida-Listas-Version`) y esa version queda grabada con la consulta: el PDF nunca la recalcula.\n\n## Autenticacion\n\nTodas las rutas `/api/v1/*` exigen `Authorization: Bearer <api_key>`. La key se emite por cliente,\nse guarda como hash SHA-256 y no se puede recuperar: si se pierde, se rota (escriba a soporte).\n\n## Errores\n\nToda respuesta de error tiene la misma forma:\n`{ \"error\": \"<codigo>\", \"message\": \"<explicacion>\", \"doc_url\": \"<ancla en /docs>\", \"request_id\": \"req_...\", \"issues\"?: [...] }`\nPrograme contra `error`; `message` puede cambiar. Codigos y cuando ocurren en la seccion Errores de /docs.\n\nNo hay rate limit por ritmo hoy (no existe 429). Vea la guia de concurrencia en /docs#concurrencia.\n\n## Consumo, cobro y bloqueo\n\n- Hay dos modalidades, y el header `X-Valida-Modalidad` dice cual tiene su cuenta. Cada respuesta de `/validate` trae headers `X-Valida-Consumo-*`.\n- **Mensual**: el paquete se mide por mes calendario (America/Bogota) y vuelve a cero el dia 1.\n- **Bolsa**: una bolsa prepagada de consultas con fecha de vencimiento (6 meses desde la entrega de credenciales), sin reinicio mensual. Se corta con lo primero que ocurra: se agota o vence. Cortada, `/validate` responde `402 bolsa_agotada` o `402 bolsa_vencida` hasta que se compre una bolsa nueva. No hay excedente y lo no usado no pasa a la siguiente bolsa.\n- **Mensual, al 100% no se bloquea**: se sigue validando y el excedente se cobra al unitario del escalon siguiente.\n- **Mensual, solo se bloquea por mora**: cuenta de cobro vencida sin pago registrado **y** consumo por encima del 100%. Entonces `/validate` responde `402 paquete_vencido_sin_pago`.\n\n## Naturaleza del servicio\n\nValida es una herramienta tecnologica de consulta automatizada. No constituye asesoria juridica ni\nsustituye el sistema SARLAFT/SAGRILAFT/SIPLAFT del sujeto obligado. El analisis de coincidencias, la\ndecision de vinculacion y el reporte a la UIAF siguen siendo responsabilidad del sujeto obligado.\n","contact":{"name":"Soporte Valida — MeTRIK SAS","email":"mauricio.moreno@metrik.com.co","url":"https://wa.me/573159509103"},"license":{"name":"Proprietary — MeTRIK SAS","identifier":"LicenseRef-MeTRIK-Commercial"}},"servers":[{"url":"https://api.valida.metrikone.co","description":"Produccion"},{"url":"http://localhost:3000","description":"Desarrollo local"}],"tags":[{"name":"Validacion","description":"Consulta de personas y entidades contra listas"},{"name":"Reportes","description":"PDF auditables con QR de verificacion y hash de integridad"},{"name":"Cuenta","description":"Consumo del paquete, historial y alertas"},{"name":"Salud","description":"Estado del servicio"}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/health":{"get":{"tags":["Salud"],"summary":"Estado del servicio","description":"Responde 200 si la aplicacion esta arriba. No verifica la base de datos.","security":[],"responses":{"200":{"description":"Servicio operativo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/validate":{"post":{"tags":["Validacion"],"summary":"Validar una persona o entidad contra todas las listas activas","description":"Compara nombre y/o documento contra la version vigente de cada lista activa. Persiste la consulta\n10 anos con hash de integridad y devuelve las coincidencias con score, tier y fundamento legal.\n\n**Reintentos seguros:** envie `Idempotency-Key` (1-64 caracteres, unico por consulta, p. ej. un UUID). Si la\nmisma clave vuelve con el mismo cuerpo dentro de 24 h, se devuelve la respuesta original con\n`X-Valida-Idempotent-Replay: true` y **no se cobra dos veces**. Misma clave con cuerpo distinto: `409 idempotency_error`.\n\n**Agregadores:** si su cliente API opera para terceros, `sujeto_obligado` es obligatorio y el PDF se emite a\nnombre de ese sujeto obligado (su razon social queda como canal).\n\n**Tiempo de respuesta:** normalmente 1-4 s; el limite del servidor es 60 s. Configure el timeout de su cliente\nen 60 s o mas y reintente solo con la misma `Idempotency-Key`.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Clave unica por consulta (1-64 chars ASCII imprimible). Recomendado: UUID v4.","schema":{"type":"string","maxLength":64}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"},"examples":{"natural":{"summary":"Persona natural con nombre y documento","value":{"tipo":"natural","nombre":"Juan Perez Gomez","documento":{"tipo":"CC","numero":"1077089147"},"fecha_nacimiento":"1985-03-15","pais":"CO","referencia_externa":"EXP-2026-00123"}},"juridica_agregador":{"summary":"Persona juridica consultada por un agregador para un sujeto obligado","value":{"tipo":"juridica","nombre":"Acme Trading SAS","documento":{"tipo":"NIT","numero":"900123456"},"sujeto_obligado":{"razon_social":"Transportes La Sabana SAS","nit":"800.123.456-7"},"referencia_externa":"vinculacion-8841"}},"solo_documento":{"summary":"Solo documento (consulta parcial)","value":{"tipo":"natural","documento":{"tipo":"CC","numero":"1077089147"}}}}}}},"responses":{"200":{"description":"Validacion completada y persistida","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}},"X-Valida-Modalidad":{"description":"mensual (paquete por mes calendario) o bolsa (bolsa prepagada con vencimiento).","schema":{"type":"string","enum":["mensual","bolsa"]}},"X-Valida-Plan":{"description":"Codigo del paquete contratado (1K, 5K, 10K, 20K, A_MEDIDA), sin_plan, o bolsa.","schema":{"type":"string"}},"X-Valida-Periodo-Inicio":{"description":"Solo modalidad mensual. Primer dia del periodo vigente (mes calendario America/Bogota). Una bolsa no lo envia: no tiene mes.","schema":{"type":"string","format":"date"}},"X-Valida-Periodo-Fin":{"description":"Solo modalidad mensual. Primer dia del periodo siguiente (exclusivo).","schema":{"type":"string","format":"date"}},"X-Valida-Bolsa-Activada-En":{"description":"Solo modalidad bolsa. Momento en que se activo la bolsa vigente.","schema":{"type":"string","format":"date-time"}},"X-Valida-Bolsa-Vence-En":{"description":"Solo modalidad bolsa. Vencimiento de la bolsa vigente: desde ese momento /validate responde 402 bolsa_vencida.","schema":{"type":"string","format":"date-time"}},"X-Valida-Consumo-Incluidas":{"description":"Mensual: consultas incluidas en el paquete. Bolsa: consultas compradas.","schema":{"type":"integer"}},"X-Valida-Consumo-Consumidas":{"description":"Consultas cobrables registradas en el periodo (mensual) o desde que se activo la bolsa (bolsa), incluida esta.","schema":{"type":"integer"}},"X-Valida-Consumo-Restante":{"description":"max(incluidas - consumidas, 0). En una bolsa es el saldo.","schema":{"type":"integer"}},"X-Valida-Consumo-Excedente":{"description":"max(consumidas - incluidas, 0). Mensual: se cobra al unitario del escalon siguiente. Bolsa: siempre 0, no hay excedente.","schema":{"type":"integer"}},"X-Valida-Consumo-Estado":{"description":"Mensual: ok | umbral_80 | agotado | excedente | bloqueado | sin_plan. Bolsa: ok | umbral_80 | agotado | vencido (agotado y vencido responden 402).","schema":{"type":"string"}},"X-Valida-Listas-Version":{"description":"slug=fecha_version;... de cada lista comparada.","schema":{"type":"string"}},"X-Valida-Idempotent-Replay":{"description":"true cuando la respuesta es la repeticion de una consulta previa con la misma Idempotency-Key.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"}}}},"400":{"description":"Cuerpo invalido (validation_error, invalid_json), falta sujeto_obligado (sujeto_obligado_requerido) o Idempotency-Key mal formada (idempotency_key_invalida).","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}},"X-Valida-Modalidad":{"description":"mensual (paquete por mes calendario) o bolsa (bolsa prepagada con vencimiento).","schema":{"type":"string","enum":["mensual","bolsa"]}},"X-Valida-Plan":{"description":"Codigo del paquete contratado (1K, 5K, 10K, 20K, A_MEDIDA), sin_plan, o bolsa.","schema":{"type":"string"}},"X-Valida-Periodo-Inicio":{"description":"Solo modalidad mensual. Primer dia del periodo vigente (mes calendario America/Bogota). Una bolsa no lo envia: no tiene mes.","schema":{"type":"string","format":"date"}},"X-Valida-Periodo-Fin":{"description":"Solo modalidad mensual. Primer dia del periodo siguiente (exclusivo).","schema":{"type":"string","format":"date"}},"X-Valida-Bolsa-Activada-En":{"description":"Solo modalidad bolsa. Momento en que se activo la bolsa vigente.","schema":{"type":"string","format":"date-time"}},"X-Valida-Bolsa-Vence-En":{"description":"Solo modalidad bolsa. Vencimiento de la bolsa vigente: desde ese momento /validate responde 402 bolsa_vencida.","schema":{"type":"string","format":"date-time"}},"X-Valida-Consumo-Incluidas":{"description":"Mensual: consultas incluidas en el paquete. Bolsa: consultas compradas.","schema":{"type":"integer"}},"X-Valida-Consumo-Consumidas":{"description":"Consultas cobrables registradas en el periodo (mensual) o desde que se activo la bolsa (bolsa), incluida esta.","schema":{"type":"integer"}},"X-Valida-Consumo-Restante":{"description":"max(incluidas - consumidas, 0). En una bolsa es el saldo.","schema":{"type":"integer"}},"X-Valida-Consumo-Excedente":{"description":"max(consumidas - incluidas, 0). Mensual: se cobra al unitario del escalon siguiente. Bolsa: siempre 0, no hay excedente.","schema":{"type":"integer"}},"X-Valida-Consumo-Estado":{"description":"Mensual: ok | umbral_80 | agotado | excedente | bloqueado | sin_plan. Bolsa: ok | umbral_80 | agotado | vencido (agotado y vencido responden 402).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"validation_error":{"value":{"error":"validation_error","message":"El cuerpo de la peticion no cumple el esquema. Revise el campo issues.","doc_url":"https://app.valida.metrikone.co/docs#error-validation_error","request_id":"req_3f9c1a2b4d5e6f708192a3b4","issues":[{"path":["nombre"],"message":"Debe enviar al menos un dato identificador: nombre o documento"}]}},"sujeto_obligado_requerido":{"value":{"error":"sujeto_obligado_requerido","message":"Este cliente opera para terceros: cada consulta debe traer sujeto_obligado { razon_social, nit } del sujeto obligado final.","doc_url":"https://app.valida.metrikone.co/docs#error-sujeto_obligado_requerido","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"402":{"description":"Consultas suspendidas. No reintente en bucle: la respuesta no cambia hasta que se registre un pago. La consulta rechazada no se registra ni se cobra.\n- `paquete_vencido_sin_pago` (mensual): cuenta de cobro vencida sin pago registrado Y consumo por encima del 100% del paquete.\n- `bolsa_agotada` (bolsa): se usaron todas las consultas de la bolsa. Tambien puede llegar si otra consulta concurrente se llevo la ultima.\n- `bolsa_vencida` (bolsa): la bolsa llego a su fecha de vencimiento, aunque le quede saldo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}},"X-Valida-Modalidad":{"description":"mensual (paquete por mes calendario) o bolsa (bolsa prepagada con vencimiento).","schema":{"type":"string","enum":["mensual","bolsa"]}},"X-Valida-Plan":{"description":"Codigo del paquete contratado (1K, 5K, 10K, 20K, A_MEDIDA), sin_plan, o bolsa.","schema":{"type":"string"}},"X-Valida-Periodo-Inicio":{"description":"Solo modalidad mensual. Primer dia del periodo vigente (mes calendario America/Bogota). Una bolsa no lo envia: no tiene mes.","schema":{"type":"string","format":"date"}},"X-Valida-Periodo-Fin":{"description":"Solo modalidad mensual. Primer dia del periodo siguiente (exclusivo).","schema":{"type":"string","format":"date"}},"X-Valida-Bolsa-Activada-En":{"description":"Solo modalidad bolsa. Momento en que se activo la bolsa vigente.","schema":{"type":"string","format":"date-time"}},"X-Valida-Bolsa-Vence-En":{"description":"Solo modalidad bolsa. Vencimiento de la bolsa vigente: desde ese momento /validate responde 402 bolsa_vencida.","schema":{"type":"string","format":"date-time"}},"X-Valida-Consumo-Incluidas":{"description":"Mensual: consultas incluidas en el paquete. Bolsa: consultas compradas.","schema":{"type":"integer"}},"X-Valida-Consumo-Consumidas":{"description":"Consultas cobrables registradas en el periodo (mensual) o desde que se activo la bolsa (bolsa), incluida esta.","schema":{"type":"integer"}},"X-Valida-Consumo-Restante":{"description":"max(incluidas - consumidas, 0). En una bolsa es el saldo.","schema":{"type":"integer"}},"X-Valida-Consumo-Excedente":{"description":"max(consumidas - incluidas, 0). Mensual: se cobra al unitario del escalon siguiente. Bolsa: siempre 0, no hay excedente.","schema":{"type":"integer"}},"X-Valida-Consumo-Estado":{"description":"Mensual: ok | umbral_80 | agotado | excedente | bloqueado | sin_plan. Bolsa: ok | umbral_80 | agotado | vencido (agotado y vencido responden 402).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ErrorPaqueteVencido"},{"$ref":"#/components/schemas/ErrorBolsaCortada"}]},"examples":{"paquete_vencido_sin_pago":{"value":{"error":"paquete_vencido_sin_pago","message":"La cuenta de cobro del paquete esta vencida sin pago registrado y el consumo supera el paquete contratado. Registre el pago con soporte para reactivar; las consultas no se pierden.","doc_url":"https://app.valida.metrikone.co/docs#error-paquete_vencido_sin_pago","request_id":"req_3f9c1a2b4d5e6f708192a3b4","consumo":{"consumidas":21340,"incluidas":20000,"restantes":0,"porcentaje":106.7,"excedente":1340,"excedente_precio_unitario":50,"excedente_valor_estimado":67000,"estado":"bloqueado"},"cobro":{"cuenta_vence_en":"2026-10-05T00:00:00Z","cuenta_referencia":"CC-0042","periodo":"2026-09-01"},"como_reactivar":"Envie el soporte de pago a mauricio.moreno@metrik.com.co o al WhatsApp +57 315 950 9103. Al registrarlo, las consultas se reactivan de inmediato y ninguna se pierde."}},"bolsa_agotada":{"value":{"error":"bolsa_agotada","message":"La bolsa de consultas se agoto. Las consultas se suspenden hasta que se registre el pago de una bolsa nueva; esta consulta no se registro ni se cobro.","doc_url":"https://app.valida.metrikone.co/docs#error-bolsa_agotada","request_id":"req_3f9c1a2b4d5e6f708192a3b4","consumo":{"consumidas":20000,"incluidas":20000,"restantes":0,"porcentaje":100,"excedente":0,"excedente_precio_unitario":null,"excedente_valor_estimado":null,"estado":"agotado"},"bolsa":{"secuencia":1,"estado":"agotada","bloqueada":true,"vence_en":"2027-03-14T20:38:51Z","consultas_compradas":20000,"consumidas":20000,"saldo":0},"como_reactivar":"Compre una bolsa nueva: escriba a mauricio.moreno@metrik.com.co o al WhatsApp +57 315 950 9103. Al registrar el pago, las consultas vuelven de inmediato. No reintente en bucle: la respuesta no cambia hasta entonces."}},"bolsa_vencida":{"value":{"error":"bolsa_vencida","message":"La bolsa de consultas vencio. Las consultas se suspenden hasta que se registre el pago de una bolsa nueva; esta consulta no se registro ni se cobro.","doc_url":"https://app.valida.metrikone.co/docs#error-bolsa_vencida","request_id":"req_3f9c1a2b4d5e6f708192a3b4","consumo":{"consumidas":12480,"incluidas":20000,"restantes":7520,"porcentaje":62.4,"excedente":0,"excedente_precio_unitario":null,"excedente_valor_estimado":null,"estado":"vencido"},"bolsa":{"secuencia":1,"estado":"vencida","bloqueada":true,"vence_en":"2027-03-14T20:38:51Z","consultas_compradas":20000,"consumidas":12480,"saldo":7520},"como_reactivar":"Compre una bolsa nueva: escriba a mauricio.moreno@metrik.com.co o al WhatsApp +57 315 950 9103. Al registrar el pago, las consultas vuelven de inmediato. No reintente en bucle: la respuesta no cambia hasta entonces."}}}}}},"409":{"description":"Idempotency-Key ya usada con un cuerpo distinto.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"idempotency_error","message":"Ya existe una consulta con esta Idempotency-Key pero con un cuerpo distinto. Use una clave nueva para una consulta distinta.","doc_url":"https://app.valida.metrikone.co/docs#error-idempotency_error","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"500":{"description":"La consulta se ejecuto pero no pudo guardarse; no se cobro. Reintente con la misma Idempotency-Key.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"persistencia_error","message":"La consulta se ejecuto pero no pudo guardarse; no se cobro. Reintente con la misma Idempotency-Key.","doc_url":"https://app.valida.metrikone.co/docs#error-persistencia_error","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}}},"/api/v1/consultas":{"get":{"tags":["Validacion"],"summary":"Listar consultas del cliente","description":"Consultas mas recientes primero. Filtre por fecha, severidad, su referencia externa o el NIT del sujeto obligado final.","parameters":[{"name":"limite","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"desde","in":"query","description":"ISO 8601; incluye consultas con creada_en >= desde.","schema":{"type":"string","format":"date-time"}},{"name":"severidad","in":"query","schema":{"type":"string","enum":["alto","medio","bajo","informativo","sin_hallazgo"]}},{"name":"referencia_externa","in":"query","description":"Coincidencia exacta con el valor enviado en /validate.","schema":{"type":"string","maxLength":128}},{"name":"sujeto_obligado_nit","in":"query","description":"NIT del sujeto obligado final (se aceptan puntos y DV; se normaliza a digitos).","schema":{"type":"string"}}],"responses":{"200":{"description":"Lista de consultas","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer","description":"Total que cumple el filtro (no solo la pagina)."},"consultas":{"type":"array","items":{"$ref":"#/components/schemas/ConsultaResumen"}}}}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"500":{"description":"Error de lectura.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"db_error","message":"...","doc_url":"https://app.valida.metrikone.co/docs#error-db_error","request_id":"req_..."}}}}}}},"/api/v1/reporte/{consulta_id}":{"get":{"tags":["Reportes"],"summary":"PDF auditable de una consulta","description":"Regenera el reporte desde la base de datos: mismos hallazgos, mismo hash, y **las versiones de lista registradas\nal consultar** (no las vigentes al descargar). Estampa al sujeto obligado final si la consulta lo trajo; si no, a su razon social.\nIncluye QR de verificacion publica.","parameters":[{"name":"consulta_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"PDF del reporte","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"404":{"description":"La consulta no existe o no pertenece al cliente autenticado.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_found","message":"El recurso no existe o no pertenece al cliente autenticado.","doc_url":"https://app.valida.metrikone.co/docs#error-not_found","request_id":"req_..."}}}},"500":{"description":"Error de lectura.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"db_error","message":"...","doc_url":"https://app.valida.metrikone.co/docs#error-db_error","request_id":"req_..."}}}}}}},"/api/v1/reporte-lote":{"post":{"tags":["Reportes"],"summary":"PDF agregado de hasta 500 consultas","description":"Un solo PDF con la distribucion de severidad y una fila por consulta, en el orden enviado. Las consultas que no existan o no sean suyas se omiten.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReporteLoteRequest"},"example":{"consulta_ids":["4f8e2a91-1c3e-4f0a-9d2b-1a2b3c4d5e6f","7b2c1d83-9e8f-4a1b-8c7d-6e5f4a3b2c1d"],"titulo":"Cargue plantilla septiembre 2026"}}}},"responses":{"200":{"description":"PDF del lote","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"invalid_json, consulta_ids_requeridos o maximo_500_consultas_por_lote.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"maximo_500_consultas_por_lote","message":"Error en la peticion.","doc_url":"https://app.valida.metrikone.co/docs#error-maximo_500_consultas_por_lote","request_id":"req_..."}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"404":{"description":"Ninguna de las consultas pertenece al cliente.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"consultas_no_encontradas_para_cliente","message":"Error en la peticion.","doc_url":"https://app.valida.metrikone.co/docs#error-consultas_no_encontradas_para_cliente","request_id":"req_..."}}}},"500":{"description":"Error de lectura o escritura.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"db_error","message":"...","doc_url":"https://app.valida.metrikone.co/docs#error-db_error","request_id":"req_..."}}}}}}},"/api/v1/cuenta/consumo":{"get":{"tags":["Cuenta"],"summary":"Consumo del paquete en el periodo vigente, o de la bolsa prepagada","description":"Contador en tiempo real (misma fuente que los headers de /validate), estado de cobro y politica aplicable.\n\nPrograme contra `modalidad`:\n- `mensual`: trae `plan` y `periodo`; `bolsa` no viene.\n- `bolsa`: trae `bolsa` (estado, compradas, consumidas, saldo, activacion y vencimiento); `plan` y `periodo` vienen en `null` porque una bolsa no tiene mes. En `consumo`, `incluidas` son las compradas y no hay excedente. Con la bolsa agotada o vencida, `cobro.bloqueado` es `true` y /validate responde 402.","responses":{"200":{"description":"Consumo actual","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}},"X-Valida-Modalidad":{"description":"mensual (paquete por mes calendario) o bolsa (bolsa prepagada con vencimiento).","schema":{"type":"string","enum":["mensual","bolsa"]}},"X-Valida-Plan":{"description":"Codigo del paquete contratado (1K, 5K, 10K, 20K, A_MEDIDA), sin_plan, o bolsa.","schema":{"type":"string"}},"X-Valida-Periodo-Inicio":{"description":"Solo modalidad mensual. Primer dia del periodo vigente (mes calendario America/Bogota). Una bolsa no lo envia: no tiene mes.","schema":{"type":"string","format":"date"}},"X-Valida-Periodo-Fin":{"description":"Solo modalidad mensual. Primer dia del periodo siguiente (exclusivo).","schema":{"type":"string","format":"date"}},"X-Valida-Bolsa-Activada-En":{"description":"Solo modalidad bolsa. Momento en que se activo la bolsa vigente.","schema":{"type":"string","format":"date-time"}},"X-Valida-Bolsa-Vence-En":{"description":"Solo modalidad bolsa. Vencimiento de la bolsa vigente: desde ese momento /validate responde 402 bolsa_vencida.","schema":{"type":"string","format":"date-time"}},"X-Valida-Consumo-Incluidas":{"description":"Mensual: consultas incluidas en el paquete. Bolsa: consultas compradas.","schema":{"type":"integer"}},"X-Valida-Consumo-Consumidas":{"description":"Consultas cobrables registradas en el periodo (mensual) o desde que se activo la bolsa (bolsa), incluida esta.","schema":{"type":"integer"}},"X-Valida-Consumo-Restante":{"description":"max(incluidas - consumidas, 0). En una bolsa es el saldo.","schema":{"type":"integer"}},"X-Valida-Consumo-Excedente":{"description":"max(consumidas - incluidas, 0). Mensual: se cobra al unitario del escalon siguiente. Bolsa: siempre 0, no hay excedente.","schema":{"type":"integer"}},"X-Valida-Consumo-Estado":{"description":"Mensual: ok | umbral_80 | agotado | excedente | bloqueado | sin_plan. Bolsa: ok | umbral_80 | agotado | vencido (agotado y vencido responden 402).","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsumoResponse"}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}},"409":{"description":"El cliente no tiene paquete mensual ni bolsa (p. ej. beta sin costo). /validate funciona igual.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"sin_plan_asignado","message":"El cliente no tiene un paquete de consultas asignado. Escriba a soporte para activarlo.","doc_url":"https://app.valida.metrikone.co/docs#error-sin_plan_asignado","request_id":"req_...","periodo":{"inicio":"2026-09-01","fin":"2026-10-01"},"consumo":{"consumidas":312}}}}}}}},"/api/v1/cuenta/consumo/historial":{"get":{"tags":["Cuenta"],"summary":"Historial de periodos, o de bolsas","description":"Mensual: periodos, mas reciente primero. Con bolsa prepagada: sus bolsas en vez de meses (modalidad bolsa), mas reciente primero; `periodos` limita cuantas.","parameters":[{"name":"periodos","in":"query","schema":{"type":"integer","minimum":1,"maximum":36,"default":6}}],"responses":{"200":{"description":"Periodos o bolsas, mas reciente primero","content":{"application/json":{"schema":{"type":"object","properties":{"modalidad":{"type":"string","enum":["bolsa"],"description":"Solo viene cuando la respuesta es de bolsas."},"total":{"type":"integer"},"periodos":{"type":"array","items":{"$ref":"#/components/schemas/PeriodoHistorial"},"description":"Solo modalidad mensual."},"bolsas":{"type":"array","items":{"$ref":"#/components/schemas/BolsaHistorial"},"description":"Solo modalidad bolsa."}}}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}}},"/api/v1/cuenta/alertas":{"get":{"tags":["Cuenta"],"summary":"Configuracion de alertas y eventos del periodo","responses":{"200":{"description":"Configuracion vigente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertasResponse"}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}},"put":{"tags":["Cuenta"],"summary":"Configurar umbrales, emails y webhook","description":"Los campos omitidos se conservan. `webhook.url` debe ser https; `webhook: { \"url\": null }` lo desactiva.\n**El secreto del webhook se devuelve una sola vez**, cuando se configura la URL por primera vez (campo `webhook.secret`). Guardelo; despues solo se puede rotar.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertasRequest"},"example":{"umbrales":[50,80,100,120],"emails":["cumplimiento@plataforma.ejemplo"],"webhook":{"url":"https://plataforma.ejemplo/valida/webhook"},"activa":true}}}},"responses":{"200":{"description":"Configuracion guardada (con webhook.secret solo la primera vez)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertasResponse"}}}},"400":{"description":"validation_error o invalid_json.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"validation_error","message":"...","doc_url":"https://app.valida.metrikone.co/docs#error-validation_error","request_id":"req_...","issues":[]}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}}},"/api/v1/cuenta/alertas/webhook/rotar-secreto":{"post":{"tags":["Cuenta"],"summary":"Rotar el secreto del webhook","description":"Devuelve un secreto nuevo (una sola vez). El anterior sigue firmando 24 h: durante ese lapso X-Valida-Signature trae dos valores v1.","responses":{"200":{"description":"Secreto nuevo","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"type":"object","properties":{"secret":{"type":"string","example":"whsec_..."},"anterior_valido_hasta":{"type":"string","format":"date-time"}}},"nota":{"type":"string"}}}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}}},"/api/v1/cuenta/alertas/prueba":{"post":{"tags":["Cuenta"],"summary":"Enviar un evento paquete.prueba a sus canales","responses":{"202":{"description":"Evento creado y primer intento de entrega ejecutado","content":{"application/json":{"schema":{"type":"object","properties":{"evento_id":{"type":"string","format":"uuid"},"tipo":{"type":"string","example":"paquete.prueba"},"entrega":{"type":"object","nullable":true,"properties":{"estado":{"type":"string"},"intentos":{"type":"integer"},"ultimo_status":{"type":"integer","nullable":true},"ultimo_error":{"type":"string","nullable":true},"email_enviado_en":{"type":"string","nullable":true}}}}}}}},"401":{"description":"API key ausente, mal formada, revocada, vencida (regenerada hace mas de 24 h) o de cliente inactivo.","headers":{"X-Valida-Request-Id":{"description":"Id unico de la peticion (req_...). Citelo en soporte.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid_api_key","message":"API key ausente, mal formada, revocada, vencida o de un cliente inactivo. Envie Authorization: Bearer <api_key>.","doc_url":"https://app.valida.metrikone.co/docs#error-invalid_api_key","request_id":"req_3f9c1a2b4d5e6f708192a3b4"}}}}}}}},"webhooks":{"paquete.*":{"post":{"summary":"Eventos de consumo que Valida envia a su webhook","description":"POST JSON a la URL configurada, timeout 10 s, exito = cualquier 2xx. Reintentos con backoff 1 min, 5 min, 30 min, 2 h, 12 h, 24 h; luego el evento queda `fallido` y se ve en GET /cuenta/alertas.\n\nHeaders: `X-Valida-Event` (tipo), `X-Valida-Delivery-Id` (cambia en cada intento; `id` del cuerpo no), `X-Valida-Signature` (`t=<unix>,v1=<hex>`; durante una rotacion, dos `v1`).\nFirma: `hex(hmac_sha256(secret, t + \".\" + cuerpo_crudo))`. Verifique en tiempo constante y rechace si `|ahora - t| > 300 s`.\nIdempotencia: puede recibir el mismo `id` mas de una vez; procese por `id`.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvento"}}}},"responses":{"200":{"description":"Recibido"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"api_key","description":"API key del cliente (`vk_` + 64 hex). Se genera, regenera y revoca en el portal de clientes (/portal); al regenerarla, la anterior sigue valida 24 h. Header `Authorization: Bearer <api_key>`."}},"schemas":{"HealthResponse":{"type":"object","required":["status","service","version","timestamp"],"properties":{"status":{"type":"string","example":"ok"},"service":{"type":"string","example":"valida"},"version":{"type":"string","example":"0.1.0"},"timestamp":{"type":"string","format":"date-time"}}},"Documento":{"type":"object","required":["tipo","numero"],"properties":{"tipo":{"type":"string","enum":["CC","CE","NIT","PAS"]},"numero":{"type":"string","minLength":3,"description":"Sin puntos ni espacios. Para NIT, sin digito de verificacion."}}},"SujetoObligado":{"type":"object","required":["razon_social","nit"],"description":"Sujeto obligado final por cuenta de quien se consulta. Obligatorio si el cliente API opera para terceros; el PDF se emite a su nombre.","properties":{"razon_social":{"type":"string","minLength":3,"maxLength":200},"nit":{"type":"string","description":"Se aceptan puntos y guion del DV (\"800.123.456-7\"); se guarda normalizado a digitos."}}},"ValidateRequest":{"type":"object","required":["tipo"],"description":"Debe traer al menos nombre o documento. Con ambos, la cobertura es completa; con uno solo la respuesta marca consulta_parcial: true.","properties":{"tipo":{"type":"string","enum":["natural","juridica"]},"nombre":{"type":"string","minLength":2,"description":"Nombre completo (natural) o razon social (juridica)."},"documento":{"$ref":"#/components/schemas/Documento"},"fecha_nacimiento":{"type":"string","format":"date","description":"YYYY-MM-DD. Solo personas naturales; mejora la desambiguacion."},"pais":{"type":"string","minLength":2,"maxLength":2,"description":"ISO 3166-1 alpha-2."},"referencia_externa":{"type":"string","minLength":1,"maxLength":128,"description":"Su identificador (expediente, fila del lote). Se devuelve y se puede filtrar en /consultas."},"sujeto_obligado":{"$ref":"#/components/schemas/SujetoObligado"}}},"ListaConsultada":{"type":"object","required":["slug","nombre","tier","version_id","hash_contenido","fetched_en","total_entradas"],"properties":{"slug":{"type":"string","example":"onu_consolidated"},"nombre":{"type":"string"},"tier":{"type":"string","enum":["1_vinculante","2_obligatoria","3_referencia"]},"version_id":{"type":"string","format":"uuid"},"hash_contenido":{"type":"string","description":"SHA-256 del contenido de la lista en esa version."},"fetched_en":{"type":"string","format":"date-time","description":"Cuando Valida descargo esa version de la fuente oficial."},"total_entradas":{"type":"integer"}}},"ValidateResponse":{"type":"object","required":["consulta_id","severidad","total_matches","consulta_parcial","matches","hash_reporte","consultado","listas_consultadas","fecha_reporte","cliente"],"properties":{"consulta_id":{"type":"string","format":"uuid","description":"Uselo para descargar el PDF en /reporte/{consulta_id}."},"severidad":{"type":"string","enum":["alto","medio","bajo","informativo","sin_hallazgo"]},"total_matches":{"type":"integer","minimum":0},"consulta_parcial":{"type":"boolean","description":"true si se envio solo nombre o solo documento."},"matches":{"type":"array","items":{"$ref":"#/components/schemas/MatchItem"}},"hash_reporte":{"type":"string","description":"SHA-256 hex; el PDF lo imprime y el QR lo verifica."},"consultado":{"type":"object","properties":{"tipo":{"type":"string","enum":["natural","juridica"]},"nombre":{"type":"string","nullable":true},"documento":{"$ref":"#/components/schemas/Documento"}}},"sujeto_obligado":{"oneOf":[{"$ref":"#/components/schemas/SujetoObligado"},{"type":"null"}]},"referencia_externa":{"type":"string","nullable":true},"listas_consultadas":{"type":"array","items":{"$ref":"#/components/schemas/ListaConsultada"}},"fecha_reporte":{"type":"string","format":"date-time"},"cliente":{"type":"string","description":"Nombre del cliente API autenticado."}}},"MatchItem":{"type":"object","required":["lista","lista_nombre","tier","vinculante_colombia","nombre_coincidencia","score","resultado","match_por"],"properties":{"lista":{"type":"string","description":"Slug estable de la lista."},"lista_nombre":{"type":"string"},"tier":{"type":"string","enum":["1_vinculante","2_obligatoria","3_referencia"]},"vinculante_colombia":{"type":"boolean"},"nombre_coincidencia":{"type":"string","description":"Nombre o alias de la entrada que genero el match."},"score":{"type":"number","minimum":0,"maximum":1,"description":"Jaro-Winkler 70% + Levenshtein 30% sobre nombres normalizados. 1.0 en match por documento."},"resultado":{"type":"string","enum":["exacto","posible"],"description":"exacto >= 0.95; posible entre 0.70 y 0.95 (requiere analisis del oficial de cumplimiento)."},"fundamento_legal":{"type":"string","nullable":true},"match_por":{"type":"string","enum":["nombre","documento"]},"documento_coincidencia":{"type":"object","nullable":true,"description":"Documento que trae la ENTRADA de la lista (dato de la coincidencia, no identidad confirmada).","properties":{"tipo":{"type":"string"},"numero":{"type":"string"},"pais":{"type":"string","nullable":true}}},"derivado":{"type":"boolean","description":"true si salio del segundo pase (re-validacion con el dato complementario hallado)."},"derivado_de":{"type":"object","nullable":true,"properties":{"tipo":{"type":"string","enum":["nombre","documento"]},"valor":{"type":"string"},"lista_nombre":{"type":"string"}}}}},"ConsultaResumen":{"type":"object","properties":{"consulta_id":{"type":"string","format":"uuid"},"nombre_consultado":{"type":"string","nullable":true},"documento_consultado":{"type":"string","nullable":true},"severidad":{"type":"string"},"total_matches":{"type":"integer"},"referencia_externa":{"type":"string","nullable":true},"sujeto_obligado_razon_social":{"type":"string","nullable":true},"sujeto_obligado_nit":{"type":"string","nullable":true},"creada_en":{"type":"string","format":"date-time"}}},"ReporteLoteRequest":{"type":"object","required":["consulta_ids"],"properties":{"consulta_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":500},"titulo":{"type":"string","maxLength":200}}},"Plan":{"type":"object","properties":{"codigo":{"type":"string","example":"20K"},"nombre":{"type":"string"},"consultas_incluidas":{"type":"integer","example":20000},"precio_mes":{"type":"number","example":1400000},"precio_unitario":{"type":"number","example":70},"precio_excedente":{"type":"number","example":50,"description":"Unitario del escalon siguiente."},"a_medida":{"type":"boolean"},"moneda":{"type":"string","example":"COP"},"iva_incluido":{"type":"boolean","example":false}}},"Consumo":{"type":"object","properties":{"consumidas":{"type":"integer","example":16420},"incluidas":{"type":"integer","example":20000,"description":"Mensual: incluidas del paquete. Bolsa: consultas compradas."},"restantes":{"type":"integer","example":3580},"porcentaje":{"type":"number","nullable":true,"example":82.1},"excedente":{"type":"integer","example":0},"excedente_precio_unitario":{"type":"number","nullable":true,"example":50,"description":"null en bolsa: no hay excedente."},"excedente_valor_estimado":{"type":"number","nullable":true,"example":0,"description":"null en bolsa."},"estado":{"type":"string","enum":["ok","umbral_80","agotado","excedente","bloqueado","sin_plan","vencido"],"description":"vencido solo en bolsa; excedente, bloqueado y sin_plan solo en mensual."},"actualizado_en":{"type":"string","format":"date-time"}}},"Bolsa":{"type":"object","description":"Bolsa prepagada vigente. Se corta con lo primero que ocurra: se agota o vence.","properties":{"bolsa_id":{"type":"string","format":"uuid"},"secuencia":{"type":"integer","example":1,"description":"1 para la primera bolsa del cliente, 2 para la siguiente recarga, etc."},"estado":{"type":"string","enum":["vigente","agotada","vencida"]},"bloqueada":{"type":"boolean","example":false,"description":"true si esta agotada o vencida: /validate responde 402."},"activada_en":{"type":"string","format":"date-time","example":"2026-09-14T20:38:51Z"},"vence_en":{"type":"string","format":"date-time","example":"2027-03-14T20:38:51Z","description":"6 meses desde la entrega de credenciales."},"dias_para_vencer":{"type":"integer","example":146,"description":"Dias que faltan, redondeado hacia arriba; 0 si ya vencio."},"consultas_compradas":{"type":"integer","example":20000},"consumidas":{"type":"integer","example":16420,"description":"Consultas cobrables desde activada_en. Nunca supera consultas_compradas."},"saldo":{"type":"integer","example":3580,"description":"consultas_compradas - consumidas. Nunca negativo."},"precio_total":{"type":"number","example":1400000},"precio_unitario":{"type":"number","example":70},"moneda":{"type":"string","example":"COP"},"iva_incluido":{"type":"boolean","example":false},"pago_referencia":{"type":"string","example":"CC-0042","description":"Referencia del pago que abrio la bolsa."},"pago_registrado_en":{"type":"string","format":"date-time"}}},"BolsaHistorial":{"type":"object","properties":{"bolsa_id":{"type":"string","format":"uuid"},"secuencia":{"type":"integer"},"estado":{"type":"string","enum":["vigente","agotada","vencida","cerrada"],"description":"cerrada = la reemplazo una recarga."},"activada_en":{"type":"string","format":"date-time"},"vence_en":{"type":"string","format":"date-time"},"cerrada_en":{"type":"string","format":"date-time","nullable":true},"consultas_compradas":{"type":"integer"},"consumidas":{"type":"integer"},"saldo":{"type":"integer"},"precio_total":{"type":"number"},"pago_referencia":{"type":"string"},"pago_registrado_en":{"type":"string","format":"date-time"}}},"ConsumoResponse":{"type":"object","properties":{"modalidad":{"type":"string","enum":["mensual","bolsa"]},"cliente":{"type":"object","properties":{"cliente_id":{"type":"string","format":"uuid"},"nombre":{"type":"string"}}},"plan":{"allOf":[{"$ref":"#/components/schemas/Plan"}],"nullable":true,"description":"null en modalidad bolsa."},"bolsa":{"allOf":[{"$ref":"#/components/schemas/Bolsa"}],"nullable":true,"description":"Solo en modalidad bolsa."},"periodo":{"type":"object","nullable":true,"description":"Solo modalidad mensual. null en bolsa: una bolsa no tiene mes ni fecha de renovacion.","properties":{"inicio":{"type":"string","format":"date","example":"2026-09-01"},"fin":{"type":"string","format":"date","example":"2026-10-01"},"zona":{"type":"string","example":"America/Bogota"},"dias_restantes":{"type":"integer"},"dia_del_periodo":{"type":"integer"},"renovacion_en":{"type":"string","example":"2026-10-01T00:00:00-05:00"}}},"consumo":{"$ref":"#/components/schemas/Consumo"},"cobro":{"type":"object","properties":{"cuenta_emitida_en":{"type":"string","format":"date-time","nullable":true},"cuenta_vence_en":{"type":"string","format":"date-time","nullable":true},"cuenta_referencia":{"type":"string","nullable":true},"pago_registrado_en":{"type":"string","format":"date-time","nullable":true},"cuenta_vencida_sin_pago":{"type":"boolean"},"bloqueado":{"type":"boolean"}}},"politica":{"type":"object","properties":{"bloqueo_por_consumo":{"type":"boolean","example":false,"description":"Mensual: false. Bolsa: true (al agotarse, 402)."},"bloqueo_por_mora":{"oneOf":[{"type":"string"},{"type":"boolean"}],"description":"Mensual: texto con la regla. Bolsa: false (se abre con el pago registrado)."},"vence":{"type":"boolean","example":true,"description":"Solo en bolsa: true."},"vencimiento":{"type":"string","description":"Solo en bolsa: la regla del vencimiento."},"excedente":{"type":"string"},"rollover":{"type":"boolean","example":false,"description":"false en las dos: lo no usado no pasa al siguiente periodo ni a la siguiente bolsa."},"ciclo":{"type":"string"},"umbrales_alerta":{"type":"array","items":{"type":"integer"}},"avisos_vencimiento_dias":{"type":"array","items":{"type":"integer"},"example":[30,7,1],"description":"Solo en bolsa: dias antes del vencimiento en que llega paquete.vencimiento_proximo."}}}}},"PeriodoHistorial":{"type":"object","properties":{"inicio":{"type":"string","format":"date"},"fin":{"type":"string","format":"date"},"plan":{"type":"string","nullable":true},"incluidas":{"type":"integer"},"consumidas":{"type":"integer"},"excedente":{"type":"integer"},"excedente_precio_unitario":{"type":"number","nullable":true},"excedente_valor":{"type":"number","nullable":true},"cobro":{"type":"object","properties":{"emitido_en":{"type":"string","nullable":true},"vence_en":{"type":"string","nullable":true},"referencia":{"type":"string","nullable":true},"pago_registrado_en":{"type":"string","nullable":true}}}}},"AlertasRequest":{"type":"object","properties":{"activa":{"type":"boolean"},"umbrales":{"type":"array","items":{"type":"integer","minimum":1,"maximum":200},"maxItems":6,"description":"% del paquete o de la bolsa. < 100 = umbral_alcanzado; 100 = agotado; > 100 = excedente (una bolsa no llega a mas de 100). Los avisos de vencimiento de una bolsa (30, 7 y 1 dias) no se configuran aqui."},"emails":{"type":"array","items":{"type":"string","format":"email"},"maxItems":10},"webhook":{"type":"object","properties":{"url":{"type":"string","format":"uri","nullable":true,"description":"https obligatorio. null desactiva."}}}}},"AlertasResponse":{"type":"object","properties":{"activa":{"type":"boolean"},"umbrales":{"type":"array","items":{"type":"integer"}},"canales":{"type":"object","properties":{"webhook":{"type":"object","properties":{"url":{"type":"string","nullable":true},"configurado":{"type":"boolean"},"secreto_anterior_valido_hasta":{"type":"string","nullable":true}}},"emails":{"type":"array","items":{"type":"string"}}}},"actualizado_en":{"type":"string","format":"date-time"},"modalidad":{"type":"string","enum":["mensual","bolsa"],"nullable":true},"bolsa_actual":{"type":"object","nullable":true,"description":"Solo modalidad bolsa. Los umbrales se miden contra la bolsa vigente y vuelven a dispararse en cada bolsa nueva; ademas se avisa por tiempo antes del vencimiento.","properties":{"bolsa_id":{"type":"string","format":"uuid"},"secuencia":{"type":"integer"},"estado":{"type":"string","enum":["vigente","agotada","vencida"]},"activada_en":{"type":"string","format":"date-time"},"vence_en":{"type":"string","format":"date-time"},"dias_para_vencer":{"type":"integer"},"avisos_vencimiento_dias":{"type":"array","items":{"type":"integer"}},"disparadas":{"type":"array","items":{"type":"object"}},"pendientes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"umbral":{"type":"integer"}}}}}},"periodo_actual":{"type":"object","nullable":true,"description":"Solo modalidad mensual.","properties":{"inicio":{"type":"string","format":"date"},"fin":{"type":"string","format":"date"},"disparadas":{"type":"array","items":{"type":"object"}},"pendientes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"umbral":{"type":"integer"}}}}}},"webhook":{"type":"object","description":"Solo en la respuesta que crea el webhook.","properties":{"secret":{"type":"string","example":"whsec_..."}}}}},"WebhookEvento":{"type":"object","required":["id","tipo","creado_en","version","cliente_id","periodo","consumo"],"properties":{"id":{"type":"string","format":"uuid","description":"Estable entre reintentos. Deduplique por este campo."},"tipo":{"type":"string","enum":["paquete.umbral_alcanzado","paquete.agotado","paquete.excedente","paquete.renovado","paquete.cobro_emitido","paquete.bloqueado","paquete.reactivado","paquete.prueba","paquete.vencimiento_proximo","paquete.vencido"],"description":"vencimiento_proximo (umbral = dias: 30, 7 o 1) y vencido solo existen en bolsa."},"creado_en":{"type":"string","format":"date-time"},"version":{"type":"string","example":"2026-09-01"},"cliente_id":{"type":"string","format":"uuid"},"modalidad":{"type":"string","enum":["mensual","bolsa"],"description":"Ausente en eventos anteriores al 2026-09-14: tratelos como mensual."},"periodo":{"type":"object","nullable":true,"description":"null en modalidad bolsa.","properties":{"inicio":{"type":"string","format":"date"},"fin":{"type":"string","format":"date"}}},"bolsa":{"type":"object","nullable":true,"description":"Solo modalidad bolsa.","properties":{"bolsa_id":{"type":"string","format":"uuid"},"secuencia":{"type":"integer"},"estado":{"type":"string","enum":["vigente","agotada","vencida"]},"activada_en":{"type":"string","format":"date-time"},"vence_en":{"type":"string","format":"date-time"},"dias_para_vencer":{"type":"integer"},"consultas_compradas":{"type":"integer"},"consumidas":{"type":"integer"},"saldo":{"type":"integer"}}},"umbral":{"type":"integer","nullable":true},"consumo":{"type":"object","properties":{"consumidas":{"type":"integer"},"incluidas":{"type":"integer"},"restantes":{"type":"integer"},"porcentaje":{"type":"number","nullable":true},"excedente":{"type":"integer"},"excedente_precio_unitario":{"type":"number"}}},"plan":{"type":"object","nullable":true,"properties":{"codigo":{"type":"string"},"consultas_incluidas":{"type":"integer"}}},"politica":{"type":"object","properties":{"bloqueo_por_consumo":{"type":"boolean","example":false},"bloqueo_por_mora":{"type":"boolean","example":true,"description":"false en bolsa."},"rollover":{"type":"boolean","example":false},"vence":{"type":"boolean","description":"Solo en bolsa: true."}}},"motivo":{"type":"string","enum":["bolsa_agotada","bolsa_vencida"],"description":"Solo en paquete.bloqueado de una bolsa."},"dias_aviso":{"type":"integer","description":"Solo en paquete.vencimiento_proximo."},"cobro":{"type":"object","description":"Solo en cobro_emitido, bloqueado y reactivado (modalidad mensual)."},"como_reactivar":{"type":"string","description":"Solo en paquete.bloqueado."},"consulta_id_detonante":{"type":"string","format":"uuid","nullable":true}}},"Error":{"type":"object","required":["error","message","doc_url","request_id"],"properties":{"error":{"type":"string","description":"Codigo estable. Programe contra este campo."},"message":{"type":"string","description":"Explicacion para humanos; puede cambiar."},"doc_url":{"type":"string","format":"uri"},"request_id":{"type":"string","example":"req_3f9c1a2b4d5e6f708192a3b4"},"issues":{"type":"array","items":{"type":"object"},"description":"Solo en validation_error: detalle por campo."}}},"ErrorBolsaCortada":{"allOf":[{"$ref":"#/components/schemas/Error"},{"type":"object","properties":{"consumo":{"$ref":"#/components/schemas/Consumo"},"bolsa":{"$ref":"#/components/schemas/Bolsa"},"como_reactivar":{"type":"string"}}}]},"ErrorPaqueteVencido":{"allOf":[{"$ref":"#/components/schemas/Error"},{"type":"object","properties":{"consumo":{"$ref":"#/components/schemas/Consumo"},"cobro":{"type":"object","properties":{"cuenta_vence_en":{"type":"string","nullable":true},"cuenta_referencia":{"type":"string","nullable":true},"periodo":{"type":"string","nullable":true}}},"como_reactivar":{"type":"string"}}}]}}}}