{
  "openapi": "3.1.0",
  "info": {
    "title": "API de consultas de Tributax para integradores",
    "version": "2026-09-23",
    "summary": "Las cinco consultas de contribuyente que Tributax expone a sistemas de terceros.",
    "description": "Contrato de las **consultas que Tributax expone a integradores externos**: identidades en RENAP, contribuyentes en el RTU, la correspondencia entre CUI y NIT, el registro completo de un contribuyente y su estado de cumplimiento (omisos).\n\nEste documento se escribe leyendo el código de la API, no una colección de Postman. Una ruta que no exista en el código no aparece aquí, y una comprobación automática de paridad falla cuando el contrato y la API se separan.\n\n### Los niveles de acceso\n\n| Nivel | Headers | Ejemplo |\n| --- | --- | --- |\n| Público | ninguno | nada de lo que cubre este contrato |\n| Integración | `x-integracion-login` + `x-integracion-token` | `POST /renap/buscar-cui`, `POST /rtu/nits`, los tres `POST /catalogos/*` |\n\nLas cinco consultas se resuelven solo con las credenciales de la integración: no se opera por cuenta de ningún contribuyente, así que ninguna pide `x-user-nit`. Cada una se habilita por separado.\n\n### Fuera de este contrato\n\nLa emisión de DTE, el alta de contribuyentes y todo lo que opera por cuenta de alguien existen en la API, pero no se ofrecen como superficie de integrador y no se documentan aquí. Las rutas de `admin/`, `accountant/` y `business/` son superficies internas. Los webhooks de proveedores de pago y los stubs de webhooks tampoco se documentan.",
    "contact": {
      "name": "Soporte de integraciones Tributax",
      "url": "https://tributax.app"
    }
  },
  "servers": [
    {
      "url": "https://dev.api.tributax.app",
      "description": "Desarrollo — el servidor por defecto de esta consola"
    },
    {
      "url": "https://api.tributax.app",
      "description": "Producción — DTE reales ante SAT"
    }
  ],
  "security": [
    {
      "integracion": [],
      "integracionToken": []
    }
  ],
  "tags": [
    {
      "name": "Usuarios y accesos",
      "description": "Alta de contribuyentes, comprobación de existencia y lectura de perfil."
    },
    {
      "name": "Facturación",
      "description": "Emisión, consulta y anulación de DTE, y selección de establecimiento emisor."
    },
    {
      "name": "Consultas",
      "description": "RENAP por CUI, RTU por NIT, y los catálogos de contribuyentes (resolución CUI/NIT, RTU completo y omisos SAT). Todas son opt-in por integración."
    }
  ],
  "paths": {
    "/renap/buscar-cui": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "summary": "Consultar una persona por CUI en RENAP",
        "operationId": "searchRenapByCui",
        "description": "Consulta RENAP por CUI a través de Tributax. Solo requiere las credenciales de la integración: **no** lleva `x-user-nit`.\n\nRequisitos previos:\n- La integración debe tener `is_renap_enabled` activo. Lo habilita un administrador de Tributax, no el integrador.\n- Límite propio de **30 peticiones por minuto y por integración**, adicional al global de 100 por 15 minutos.\n\nCada consulta se registra.\n\nEsta ruta responde con la clave **`error`**, no con `message` como el resto de la API.",
        "security": [
          {
            "integracion": [],
            "integracionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cui"
                ],
                "properties": {
                  "cui": {
                    "type": "string",
                    "description": "Código Único de Identificación de la persona."
                  }
                }
              },
              "example": {
                "cui": "<CUI>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado de RENAP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResponse"
                },
                "example": {
                  "success": true,
                  "data": {
                    "cui": "<CUI>"
                  },
                  "message": "<MENSAJE DE RENAP>",
                  "responseCode": 200
                }
              }
            }
          },
          "400": {
            "description": "Falta el CUI.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceErrorResponse"
                },
                "example": {
                  "error": "CUI is required"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/ServicioNoHabilitadoRenap"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "description": "Fallo al consultar RENAP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/rtu/nits": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "summary": "Consultar contribuyentes por NIT en el RTU",
        "operationId": "searchRtuByNits",
        "description": "Consulta hasta **50 NIT** por petición en el Registro Tributario Unificado a través de Tributax. Solo requiere las credenciales de la integración: **no** lleva `x-user-nit`.\n\nRequisitos previos:\n- La integración debe tener `is_rtu_enabled` activo. Lo habilita un administrador de Tributax, no el integrador.\n- Límite propio de **50 peticiones por minuto y por integración**, adicional al global de 100 por 15 minutos.\n\nCada consulta se registra.\n\nEl status HTTP de la respuesta es el `responseCode` del cuerpo: una consulta sin coincidencias no es un error de transporte.",
        "security": [
          {
            "integracion": [],
            "integracionToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "nits"
                ],
                "properties": {
                  "nits": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 50,
                    "description": "NIT a consultar. Máximo 50 por petición."
                  }
                }
              },
              "example": {
                "nits": [
                  "<NIT>"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registros encontrados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResponse"
                },
                "example": {
                  "success": true,
                  "data": [
                    {
                      "nit": "<NIT>"
                    }
                  ],
                  "message": "Found 1 RTU records out of 1 requested",
                  "responseCode": 200
                }
              }
            }
          },
          "400": {
            "description": "`nits` ausente, vacío, no es un array, o excede los 50 elementos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceErrorResponse"
                },
                "examples": {
                  "faltaArray": {
                    "summary": "Rechazado por la ruta",
                    "value": {
                      "error": "Array of NITs is required"
                    }
                  },
                  "demasiados": {
                    "summary": "Rechazado por el cliente RTU",
                    "value": {
                      "success": false,
                      "message": "Máximo 50 NITs por petición",
                      "responseCode": 400,
                      "data": null
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/ServicioNoHabilitadoRtu"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "description": "Fallo al consultar el RTU.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/catalogos/cui-nit": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "summary": "Resolver CUI y NIT entre sí",
        "operationId": "lookupCuiNit",
        "description": "Dado un NIT, devuelve el CUI de la persona asociada; dado un CUI, devuelve su NIT — a través de Tributax. Solo requiere las credenciales de la integración: **no** lleva `x-user-nit`.\n\nEnvía `nit`, `cui`, o los dos: la petición exige que al menos uno llegue con un valor no vacío (ver el cuerpo de la petición para la regla exacta).\n\nRequisitos previos:\n- La integración debe tener `is_cui_nit_enabled` activo. Lo habilita un administrador de Tributax, no el integrador.\n- Límite propio de **30 peticiones por minuto y por integración**. Este contador es **compartido** entre `/catalogos/cui-nit`, `/catalogos/rtu` y `/catalogos/omisos`: no son cupos independientes, las tres rutas gastan del mismo contador. Adicional al límite global de 100 peticiones por 15 minutos.\n\nCada consulta se registra.\n\nEsta ruta responde con la clave **`message`**, no con `error` como `/renap/buscar-cui` y `/rtu/nits`. Si tu integración ya parsea esas dos rutas, no reutilices ese código aquí: la clave es distinta tanto en los errores propios de esta API como en los que llegan traducidos desde la fuente consultada.\n\nUn `404` se devuelve cuando la fuente no reporta resultado para los datos enviados, sea porque no hay registro o porque marcó la consulta como fallida: los dos casos comparten status y mensaje, así que no se distinguen desde tu lado. Trátalo como «no tengo el dato ahora», no como «este contribuyente no existe». Si la fuente responde que la consulta fue exitosa pero sin datos reconocibles, la respuesta no es un `404` sino un `200` con todos los campos en `null`.",
        "security": [
          {
            "integracion": [],
            "integracionToken": []
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/CatalogoConsultaRequest"
        },
        "responses": {
          "200": {
            "description": "Resultado de la consulta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CuiNitResponse"
                },
                "example": {
                  "data": {
                    "cui": "<CUI>",
                    "nit": "<NIT>",
                    "nombre": "<NOMBRES>, <APELLIDOS>",
                    "tipoPersona": "individual",
                    "fechaConsulta": "2026-09-15T15:06:28Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/CatalogoDatosInvalidos"
          },
          "401": {
            "$ref": "#/components/responses/CatalogoAutenticacionFallida"
          },
          "402": {
            "$ref": "#/components/responses/CatalogoSinSaldo"
          },
          "403": {
            "$ref": "#/components/responses/CatalogoAccesoDenegado"
          },
          "404": {
            "$ref": "#/components/responses/CatalogoSinResultado"
          },
          "429": {
            "$ref": "#/components/responses/CatalogoLimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/CatalogoFalloNoControlado"
          },
          "502": {
            "$ref": "#/components/responses/CatalogoProveedorNoDisponible"
          }
        }
      }
    },
    "/catalogos/rtu": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "summary": "Consultar el RTU completo de un contribuyente",
        "operationId": "lookupRtuV2",
        "description": "Consulta el registro tributario completo de un contribuyente en el RTU: régimen, afiliaciones, obligaciones y rasgos especiales, a través de Tributax. Es un catálogo independiente de `POST /rtu/nits`: usa una fuente distinta y su propia bandera de habilitación. Solo requiere las credenciales de la integración: **no** lleva `x-user-nit`.\n\nEnvía `nit`, `cui`, o los dos: la petición exige que al menos uno llegue con un valor no vacío (ver el cuerpo de la petición para la regla exacta).\n\nRequisitos previos:\n- La integración debe tener `is_rtu_v2_enabled` activo. Lo habilita un administrador de Tributax, no el integrador.\n- Límite propio de **30 peticiones por minuto y por integración**. Este contador es **compartido** entre `/catalogos/cui-nit`, `/catalogos/rtu` y `/catalogos/omisos`: no son cupos independientes, las tres rutas gastan del mismo contador. Adicional al límite global de 100 peticiones por 15 minutos.\n\nCada consulta se registra.\n\nEsta ruta responde con la clave **`message`**, no con `error` como `/renap/buscar-cui` y `/rtu/nits`. Si tu integración ya parsea esas dos rutas, no reutilices ese código aquí: la clave es distinta tanto en los errores propios de esta API como en los que llegan traducidos desde la fuente consultada.\n\nUn `404` se devuelve cuando la fuente no reporta resultado para los datos enviados, sea porque no hay registro o porque marcó la consulta como fallida: los dos casos comparten status y mensaje, así que no se distinguen desde tu lado. Trátalo como «no tengo el dato ahora», no como «este contribuyente no existe». Si la fuente responde que la consulta fue exitosa pero sin datos reconocibles, la respuesta no es un `404` sino un `200` con todos los campos en `null`.",
        "security": [
          {
            "integracion": [],
            "integracionToken": []
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/CatalogoRtuConsultaRequest"
        },
        "responses": {
          "200": {
            "description": "Resultado de la consulta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RtuResponse"
                },
                "example": {
                  "data": {
                    "nit": "<NIT>",
                    "tipoContribuyente": {
                      "codigo": "1",
                      "descripcion": "PERSONA/NEGOCIO"
                    },
                    "persona": {
                      "primerNombre": "<PRIMER_NOMBRE>",
                      "segundoNombre": "<SEGUNDO_NOMBRE>",
                      "primerApellido": "<PRIMER_APELLIDO>",
                      "segundoApellido": "<SEGUNDO_APELLIDO>",
                      "dpi": "<CUI>",
                      "serieDpi": null,
                      "versionDpi": null,
                      "fechaNacimiento": "1990-01-31",
                      "fechaVencimientoDpi": null,
                      "genero": {
                        "codigo": 1383,
                        "descripcion": "MASCULINO"
                      },
                      "estadoCivil": {
                        "codigo": null,
                        "descripcion": null
                      },
                      "nacionalidad": {
                        "codigo": null,
                        "descripcion": null
                      },
                      "tipoDocumento": {
                        "codigo": null,
                        "descripcion": null
                      },
                      "estado": {
                        "codigo": null,
                        "descripcion": null
                      },
                      "sectorEconomico": {
                        "codigo": 750,
                        "descripcion": "SERVICIOS",
                        "estado": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "fechaInicio": null
                      },
                      "actividadesEconomicas": [
                        {
                          "ciiu": "8411.40",
                          "nombre": "ADMINISTRACION PUBLICA",
                          "clasificacion": null
                        }
                      ],
                      "marcas": [
                        {
                          "codigo": 915,
                          "nombre": "RATIFICADO/ACTUALIZADO",
                          "estado": null,
                          "fechaEstado": null,
                          "vigenciaDesde": null,
                          "vigenciaHasta": null
                        }
                      ],
                      "participacionGremial": null,
                      "participacionEmpresarial": null
                    },
                    "empresa": null,
                    "representantes": [],
                    "afiliaciones": {
                      "isr": null,
                      "iva": {
                        "impuesto": {
                          "codigo": "11",
                          "descripcion": "IMPUESTO AL VALOR AGREGADO"
                        },
                        "regimen": {
                          "codigo": "818",
                          "descripcion": "PEQUEÑO CONTRIBUYENTE"
                        },
                        "tipoContribuyente": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "periodoImpositivo": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "formaCalculo": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "estatusAfiliacion": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "tipoRenta": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "tipoEstablecimiento": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "exento": false,
                        "fechaDesde": null,
                        "obligaciones": [
                          {
                            "nombre": "IVA PEQUEÑO CONTRIBUYENTE",
                            "periodo": null,
                            "formulario": null,
                            "generaEtiquetaOmiso": true,
                            "requerida": null,
                            "estado": {
                              "codigo": null,
                              "descripcion": null
                            }
                          }
                        ]
                      }
                    },
                    "caracteristicasEspeciales": [
                      {
                        "codigo": 2432,
                        "nombre": "EMISOR DE FACTURA ELECTRÓNICA",
                        "estado": {
                          "codigo": null,
                          "descripcion": null
                        },
                        "fechaEstado": null,
                        "fechaDesde": null,
                        "fechaHasta": null
                      }
                    ],
                    "fechaUltimaActualizacion": null,
                    "fechaConsulta": "2026-09-15T15:19:56Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/CatalogoDatosInvalidos"
          },
          "401": {
            "$ref": "#/components/responses/CatalogoAutenticacionFallida"
          },
          "402": {
            "$ref": "#/components/responses/CatalogoSinSaldo"
          },
          "403": {
            "$ref": "#/components/responses/CatalogoAccesoDenegado"
          },
          "404": {
            "$ref": "#/components/responses/CatalogoSinResultado"
          },
          "429": {
            "$ref": "#/components/responses/CatalogoLimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/CatalogoFalloNoControlado"
          },
          "502": {
            "$ref": "#/components/responses/CatalogoProveedorNoDisponible"
          }
        }
      }
    },
    "/catalogos/omisos": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "summary": "Consultar el estado de cumplimiento (omisos) de un contribuyente",
        "operationId": "lookupOmisos",
        "description": "Consulta si SAT registra obligaciones sin presentar o un proceso de cobro para un contribuyente, a través de Tributax. Solo requiere las credenciales de la integración: **no** lleva `x-user-nit`.\n\nEnvía `nit`, `cui`, o los dos: la petición exige que al menos uno llegue con un valor no vacío (ver el cuerpo de la petición para la regla exacta).\n\nRequisitos previos:\n- La integración debe tener `is_omisos_enabled` activo. Lo habilita un administrador de Tributax, no el integrador.\n- Límite propio de **30 peticiones por minuto y por integración**. Este contador es **compartido** entre `/catalogos/cui-nit`, `/catalogos/rtu` y `/catalogos/omisos`: no son cupos independientes, las tres rutas gastan del mismo contador. Adicional al límite global de 100 peticiones por 15 minutos.\n\nCada consulta se registra.\n\nEsta ruta responde con la clave **`message`**, no con `error` como `/renap/buscar-cui` y `/rtu/nits`. Si tu integración ya parsea esas dos rutas, no reutilices ese código aquí: la clave es distinta tanto en los errores propios de esta API como en los que llegan traducidos desde la fuente consultada.\n\nUn `404` se devuelve cuando la fuente no reporta resultado para los datos enviados, sea porque no hay registro o porque marcó la consulta como fallida: los dos casos comparten status y mensaje, así que no se distinguen desde tu lado. Trátalo como «no tengo el dato ahora», no como «este contribuyente no existe». Si la fuente responde que la consulta fue exitosa pero sin datos reconocibles, la respuesta no es un `404` sino un `200` con todos los campos en `null`.",
        "security": [
          {
            "integracion": [],
            "integracionToken": []
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/CatalogoConsultaRequest"
        },
        "responses": {
          "200": {
            "description": "Resultado de la consulta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OmisosResponse"
                },
                "example": {
                  "data": {
                    "nit": "<NIT>",
                    "nombre": "<NOMBRES>, <APELLIDOS>",
                    "nombreComercial": null,
                    "cui": "<CUI>",
                    "versionDpi": "002",
                    "estadoContribuyente": null,
                    "tipoAfiliacion": null,
                    "regimen": null,
                    "fechaAfiliacion": null,
                    "domicilioFiscal": {
                      "departamento": null,
                      "municipio": null,
                      "direccion": null,
                      "telefono": null
                    },
                    "establecimientos": [],
                    "tieneIncumplimientos": true,
                    "tieneProcesoCoactivo": false,
                    "incumplimientos": [
                      "DECLARACIONES OMITIDAS"
                    ],
                    "fechaConsulta": "2026-09-15T02:25:12Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/CatalogoDatosInvalidos"
          },
          "401": {
            "$ref": "#/components/responses/CatalogoAutenticacionFallida"
          },
          "402": {
            "$ref": "#/components/responses/CatalogoSinSaldo"
          },
          "403": {
            "$ref": "#/components/responses/CatalogoAccesoDenegado"
          },
          "404": {
            "$ref": "#/components/responses/CatalogoSinResultado"
          },
          "429": {
            "$ref": "#/components/responses/CatalogoLimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/CatalogoFalloNoControlado"
          },
          "502": {
            "$ref": "#/components/responses/CatalogoProveedorNoDisponible"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "integracion": {
        "type": "apiKey",
        "in": "header",
        "name": "x-integracion-login",
        "description": "Nombre de la integración, comparado en minúsculas contra `Integracion.nombre`. Es la mitad pública del modo «integrador»: viaja **siempre** junto a `x-integracion-token` (esquema `integracionToken`) y, en las rutas que operan por cuenta de un contribuyente, junto a `x-user-nit` o `x-user` (esquema `usuarioNit`). Los tres headers son el modo de autenticación completo; ninguno sirve por separado."
      },
      "integracionToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-integracion-token",
        "description": "Secreto de la integración, comparado con bcrypt contra `Integracion.token`. No se envía nunca por query string ni por cuerpo."
      }
    },
    "responses": {
      "ServicioNoHabilitadoRenap": {
        "description": "Faltan las credenciales de integración, o la integración no tiene RENAP habilitado.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ServiceErrorResponse"
            },
            "examples": {
              "sinCredenciales": {
                "value": {
                  "error": "Integration authentication required."
                }
              },
              "noHabilitado": {
                "value": {
                  "error": "RENAP access not enabled."
                }
              }
            }
          }
        }
      },
      "ServicioNoHabilitadoRtu": {
        "description": "Faltan las credenciales de integración, o la integración no tiene RTU habilitado.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ServiceErrorResponse"
            },
            "examples": {
              "sinCredenciales": {
                "value": {
                  "error": "Integration authentication required."
                }
              },
              "noHabilitado": {
                "value": {
                  "error": "RTU access not enabled."
                }
              }
            }
          }
        }
      },
      "LimiteExcedido": {
        "description": "Se superó el límite por minuto de esta integración.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ServiceErrorResponse"
            },
            "example": {
              "error": "Rate limit exceeded."
            }
          }
        }
      },
      "CatalogoDatosInvalidos": {
        "description": "La petición no trae un identificador utilizable, o la fuente consultada rechazó los datos enviados.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "sinIdentificador": {
                "summary": "Ni nit ni cui llegaron con un valor utilizable",
                "value": {
                  "message": "Envia un NIT o un CUI para consultar."
                }
              },
              "datosInvalidos": {
                "summary": "La fuente consultada rechazó los datos enviados",
                "value": {
                  "message": "Los datos de la consulta no son validos."
                }
              }
            }
          }
        }
      },
      "CatalogoAutenticacionFallida": {
        "description": "Dos causas opuestas comparten este status. Si el mensaje habla de la integración, las credenciales que enviaste no corresponden a ninguna: revísalas, y revisa el entorno contra el que estás pegando. Si dice que no fue posible autenticar la consulta, tus credenciales están bien y falló la autenticación contra la fuente: escribe a soporte de Tributax.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "credencialesInvalidas": {
                "summary": "Las credenciales de integración enviadas no corresponden a ninguna integración; también ocurre si envías solo uno de los dos headers",
                "value": {
                  "message": "Integración no encontrada con estas credenciales."
                }
              },
              "fuenteNoAutentico": {
                "summary": "La fuente consultada rechazó la autenticación de Tributax",
                "value": {
                  "message": "No fue posible autenticar la consulta. Escribe a soporte."
                }
              }
            }
          }
        }
      },
      "CatalogoSinSaldo": {
        "description": "Dos causas distintas comparten este status, y se distinguen por el mensaje. Si habla de **tu integración**, tu saldo se agotó: escribe a soporte de Tributax para recargarlo. Si habla del **servicio de consultas**, el saldo agotado es del lado de Tributax: escribe a soporte, no es algo que tu integración pueda resolver. En los dos casos la consulta no se ejecutó y no se te cobró.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "integracionSinSaldo": {
                "summary": "El saldo prepago de tu integración se agotó",
                "value": {
                  "message": "Tu integracion no tiene saldo disponible. Recarga para seguir consultando."
                }
              },
              "servicioSinSaldo": {
                "summary": "El servicio de consultas se quedó sin saldo",
                "value": {
                  "message": "El servicio de consultas no tiene saldo disponible. Escribe a soporte."
                }
              }
            }
          }
        }
      },
      "CatalogoAccesoDenegado": {
        "description": "Faltan las credenciales de integración, tu integración no tiene este catálogo contratado, o la fuente consultada no tiene este tipo de consulta habilitada.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "sinCredenciales": {
                "summary": "No se enviaron credenciales de integración",
                "value": {
                  "message": "Se requieren credenciales de integracion."
                }
              },
              "noHabilitadoIntegracion": {
                "summary": "Tu integración no tiene este catálogo contratado",
                "value": {
                  "message": "Esta consulta no esta habilitada para tu integracion."
                }
              },
              "noHabilitadoFuente": {
                "summary": "La fuente consultada rechaza este tipo de consulta",
                "value": {
                  "message": "Esta consulta no esta habilitada. Escribe a soporte."
                }
              }
            }
          }
        }
      },
      "CatalogoSinResultado": {
        "description": "No se encontró información para los datos enviados. También se devuelve cuando la fuente respondió pero el registro llegó vacío o marcado como fallido: desde este lado, los dos casos son indistinguibles de un 404 normal.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "No encontramos informacion para los datos enviados."
            }
          }
        }
      },
      "CatalogoLimiteExcedido": {
        "description": "Se superó un límite de consultas. Hay dos límites distintos detrás del mismo status: el propio de esta API (por integración) y el de la fuente consultada — el mensaje indica cuál.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "limitePropio": {
                "summary": "Límite propio de Tributax: 30 por minuto, compartido entre los tres catálogos",
                "value": {
                  "message": "Demasiadas consultas seguidas. Intenta en un minuto."
                }
              },
              "limiteFuente": {
                "summary": "Límite de la fuente consultada",
                "value": {
                  "message": "Demasiadas consultas seguidas. Intenta de nuevo en unos minutos."
                }
              }
            }
          }
        }
      },
      "CatalogoProveedorNoDisponible": {
        "description": "El servicio de consultas no respondió o falló del lado de la fuente. Reintenta más tarde.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "El servicio de consultas no esta disponible en este momento."
            }
          }
        }
      },
      "CatalogoFalloNoControlado": {
        "description": "Fallo no controlado de la API. El mensaje no es fijo: no lo uses como condición. Es distinto del `502`, que señala a la fuente.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Algo salió mal"
            }
          }
        }
      }
    },
    "requestBodies": {
      "CatalogoConsultaRequest": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CatalogoConsulta"
            },
            "example": {
              "nit": "<NIT>"
            }
          }
        }
      },
      "CatalogoRtuConsultaRequest": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/CatalogoConsulta"
                },
                {
                  "type": "object",
                  "properties": {
                    "date_of_birth": {
                      "type": "string",
                      "format": "date",
                      "description": "Fecha de nacimiento de la persona individual, o de constitución de la persona jurídica, en `YYYY-MM-DD`. Opcional: la fuente la pide solo cuando no tiene una copia del registro, y puede resolverla por su cuenta si tu integración tiene habilitadas otras consultas. Solo la lee esta ruta: `/catalogos/cui-nit` y `/catalogos/omisos` la descartan. Tributax no valida su formato; la reenvía tal como llega."
                    }
                  }
                }
              ]
            },
            "example": {
              "nit": "<NIT>"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Forma normal de un error: el manejador global responde solo `message`.",
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ]
      },
      "ServiceErrorResponse": {
        "type": "object",
        "description": "Forma de error de RENAP y RTU: la clave es `error` y su valor es texto, no un booleano.",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "LookupResponse": {
        "type": "object",
        "description": "Forma común de RENAP y RTU.\n\nEn **RTU** el status HTTP replica `responseCode`. En **RENAP** no: el status es el status HTTP con el que contestó RENAP, mientras que `responseCode` es un campo del cuerpo de RENAP y `success` se calcula del status HTTP. Un `200` con `success: true` puede llevar un `responseCode` de error — comprueba los dos.",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "data": {
            "description": "Registros encontrados, o `null`."
          },
          "message": {
            "type": "string"
          },
          "responseCode": {
            "type": "integer"
          }
        }
      },
      "CodigoDescripcion": {
        "type": "object",
        "description": "Un valor catalogado por SAT: `codigo` sirve para máquinas y `descripcion` para personas. `codigo` llega como número o como texto según el catálogo de SAT: compáralo por valor, no por tipo. Si SAT no informa el valor, los dos campos salen `null`; el objeto siempre está.",
        "required": [
          "codigo",
          "descripcion"
        ],
        "properties": {
          "codigo": {
            "type": [
              "number",
              "string",
              "null"
            ],
            "description": "Código de SAT."
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Texto de SAT para ese código."
          }
        }
      },
      "CuiNitResultado": {
        "type": "object",
        "description": "Correspondencia entre el CUI y el NIT de un contribuyente.",
        "required": [
          "cui",
          "nit",
          "nombre",
          "tipoPersona",
          "fechaConsulta"
        ],
        "properties": {
          "cui": {
            "type": [
              "string",
              "null"
            ],
            "description": "CUI del contribuyente."
          },
          "nit": {
            "type": [
              "string",
              "null"
            ],
            "description": "NIT del contribuyente."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre del contribuyente como lo registra la fuente."
          },
          "tipoPersona": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "individual",
              "juridica",
              null
            ],
            "description": "`individual` o `juridica`. `null` si la fuente no lo informa o informa un valor que no se reconoce."
          },
          "fechaConsulta": {
            "type": [
              "string",
              "null"
            ],
            "description": "Momento que la fuente reporta para el dato. No es necesariamente el momento de tu petición: con `actualizado: false` la respuesta puede venir de una copia anterior. Se entrega tal como lo publica la fuente —hoy, en ISO 8601 con zona UTC—, pero el formato no lo normaliza Tributax: trátalo como texto y no lo parsees sin haberlo comprobado en tu propia integración."
          }
        }
      },
      "DomicilioFiscal": {
        "type": "object",
        "description": "Domicilio fiscal registrado ante SAT. El objeto siempre está; sus campos pueden venir `null`.",
        "required": [
          "departamento",
          "municipio",
          "direccion",
          "telefono"
        ],
        "properties": {
          "departamento": {
            "type": [
              "string",
              "null"
            ],
            "description": "Departamento."
          },
          "municipio": {
            "type": [
              "string",
              "null"
            ],
            "description": "Municipio."
          },
          "direccion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Dirección."
          },
          "telefono": {
            "type": [
              "string",
              "null"
            ],
            "description": "Teléfono registrado."
          }
        }
      },
      "OmisosResultado": {
        "type": "object",
        "description": "Estado de cumplimiento de un contribuyente ante SAT. Lo que se consulta de verdad son `tieneIncumplimientos` y `tieneProcesoCoactivo`.",
        "required": [
          "nit",
          "nombre",
          "nombreComercial",
          "cui",
          "versionDpi",
          "estadoContribuyente",
          "tipoAfiliacion",
          "regimen",
          "fechaAfiliacion",
          "domicilioFiscal",
          "establecimientos",
          "tieneIncumplimientos",
          "tieneProcesoCoactivo",
          "incumplimientos",
          "fechaConsulta"
        ],
        "properties": {
          "nit": {
            "type": [
              "string",
              "null"
            ],
            "description": "NIT del contribuyente."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre del contribuyente."
          },
          "nombreComercial": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre comercial, si tiene."
          },
          "cui": {
            "type": [
              "string",
              "null"
            ],
            "description": "CUI tal como lo publica la fuente: puede venir con espacios entre grupos de dígitos."
          },
          "versionDpi": {
            "type": [
              "string",
              "null"
            ],
            "description": "Versión del DPI."
          },
          "estadoContribuyente": {
            "type": [
              "string",
              "null"
            ],
            "description": "Estado del contribuyente según SAT."
          },
          "tipoAfiliacion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tipo de afiliación."
          },
          "regimen": {
            "type": [
              "string",
              "null"
            ],
            "description": "Régimen, como texto."
          },
          "fechaAfiliacion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "domicilioFiscal": {
            "$ref": "#/components/schemas/DomicilioFiscal"
          },
          "establecimientos": {
            "type": "array",
            "items": {},
            "description": "Establecimientos del contribuyente. Se entrega tal como lo publica la fuente, sin normalizar: su forma todavía no está fijada en este contrato y puede cambiar. Lista vacía si no hay."
          },
          "tieneIncumplimientos": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si SAT registra obligaciones sin presentar. `null` significa que la fuente no lo informó: no lo trates como `false`."
          },
          "tieneProcesoCoactivo": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si SAT registra un proceso de cobro coactivo. `null` significa que la fuente no lo informó: no lo trates como `false`."
          },
          "incumplimientos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Detalle de los incumplimientos, como texto de SAT (p. ej. `DECLARACIONES OMITIDAS`). Lista vacía, nunca `null`, cuando no hay."
          },
          "fechaConsulta": {
            "type": [
              "string",
              "null"
            ],
            "description": "Momento que la fuente reporta para el dato. No es necesariamente el momento de tu petición: con `actualizado: false` la respuesta puede venir de una copia anterior. Se entrega tal como lo publica la fuente —hoy, en ISO 8601 con zona UTC—, pero el formato no lo normaliza Tributax: trátalo como texto y no lo parsees sin haberlo comprobado en tu propia integración."
          }
        }
      },
      "ActividadEconomica": {
        "type": "object",
        "description": "Actividad económica registrada.",
        "required": [
          "ciiu",
          "nombre",
          "clasificacion"
        ],
        "properties": {
          "ciiu": {
            "type": [
              "string",
              "null"
            ],
            "description": "Código CIIU de la actividad."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre de la actividad."
          },
          "clasificacion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Clasificación de la actividad."
          }
        }
      },
      "MarcaContribuyente": {
        "type": "object",
        "description": "Marca que SAT asigna al contribuyente (p. ej. ratificado o actualizado).",
        "required": [
          "codigo",
          "nombre",
          "estado",
          "fechaEstado",
          "vigenciaDesde",
          "vigenciaHasta"
        ],
        "properties": {
          "codigo": {
            "type": [
              "number",
              "null"
            ],
            "description": "Código de la marca."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre de la marca."
          },
          "estado": {
            "type": [
              "number",
              "null"
            ],
            "description": "Estado de la marca, como código numérico de SAT."
          },
          "fechaEstado": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "vigenciaDesde": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "vigenciaHasta": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          }
        }
      },
      "SectorEconomico": {
        "type": "object",
        "description": "Sector económico del contribuyente. El objeto siempre está; sus campos pueden venir `null`.",
        "required": [
          "codigo",
          "descripcion",
          "estado",
          "fechaInicio"
        ],
        "properties": {
          "codigo": {
            "type": [
              "number",
              "null"
            ],
            "description": "Código del sector."
          },
          "descripcion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre del sector."
          },
          "estado": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "fechaInicio": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          }
        }
      },
      "PersonaRtu": {
        "type": "object",
        "description": "Datos de una persona individual en el RTU.",
        "required": [
          "primerNombre",
          "segundoNombre",
          "primerApellido",
          "segundoApellido",
          "dpi",
          "serieDpi",
          "versionDpi",
          "fechaNacimiento",
          "fechaVencimientoDpi",
          "genero",
          "estadoCivil",
          "nacionalidad",
          "tipoDocumento",
          "estado",
          "sectorEconomico",
          "actividadesEconomicas",
          "marcas",
          "participacionGremial",
          "participacionEmpresarial"
        ],
        "properties": {
          "primerNombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Primer nombre."
          },
          "segundoNombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Segundo nombre."
          },
          "primerApellido": {
            "type": [
              "string",
              "null"
            ],
            "description": "Primer apellido."
          },
          "segundoApellido": {
            "type": [
              "string",
              "null"
            ],
            "description": "Segundo apellido."
          },
          "dpi": {
            "type": [
              "string",
              "null"
            ],
            "description": "Número de DPI (CUI)."
          },
          "serieDpi": {
            "type": [
              "string",
              "null"
            ],
            "description": "Serie del DPI."
          },
          "versionDpi": {
            "type": [
              "string",
              "null"
            ],
            "description": "Versión del DPI."
          },
          "fechaNacimiento": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Fecha de nacimiento, `YYYY-MM-DD`."
          },
          "fechaVencimientoDpi": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "genero": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "estadoCivil": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "nacionalidad": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "tipoDocumento": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "estado": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "sectorEconomico": {
            "$ref": "#/components/schemas/SectorEconomico"
          },
          "actividadesEconomicas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActividadEconomica"
            },
            "description": "Actividades económicas. Lista vacía si no hay."
          },
          "marcas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MarcaContribuyente"
            },
            "description": "Marcas del contribuyente. Lista vacía si no hay."
          },
          "participacionGremial": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si participa en una gremial."
          },
          "participacionEmpresarial": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si participa en una empresa."
          }
        }
      },
      "ObligacionTributaria": {
        "type": "object",
        "description": "Obligación que la afiliación le impone al contribuyente.",
        "required": [
          "nombre",
          "periodo",
          "formulario",
          "generaEtiquetaOmiso",
          "requerida",
          "estado"
        ],
        "properties": {
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre de la obligación."
          },
          "periodo": {
            "type": [
              "string",
              "null"
            ],
            "description": "Periodicidad de la obligación."
          },
          "formulario": {
            "type": [
              "string",
              "null"
            ],
            "description": "Formulario con que se cumple."
          },
          "generaEtiquetaOmiso": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si incumplirla deja al contribuyente marcado como omiso."
          },
          "requerida": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si la obligación es requerida."
          },
          "estado": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          }
        }
      },
      "AfiliacionImpuesto": {
        "type": "object",
        "description": "Afiliación del contribuyente a un impuesto. ISR e IVA comparten esta forma; los campos que solo aplican a uno de los dos salen con `codigo` y `descripcion` en `null` en el otro.",
        "required": [
          "impuesto",
          "regimen",
          "tipoContribuyente",
          "periodoImpositivo",
          "formaCalculo",
          "estatusAfiliacion",
          "tipoRenta",
          "tipoEstablecimiento",
          "exento",
          "fechaDesde",
          "obligaciones"
        ],
        "properties": {
          "impuesto": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "regimen": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "tipoContribuyente": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "periodoImpositivo": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "formaCalculo": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "estatusAfiliacion": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "tipoRenta": {
            "description": "Solo ISR.",
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "tipoEstablecimiento": {
            "description": "Solo IVA.",
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "exento": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Si está exento."
          },
          "fechaDesde": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "obligaciones": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ObligacionTributaria"
            },
            "description": "Obligaciones de esta afiliación. Lista vacía si no hay."
          }
        }
      },
      "CaracteristicaEspecial": {
        "type": "object",
        "description": "Característica especial registrada (p. ej. emisor de factura electrónica).",
        "required": [
          "codigo",
          "nombre",
          "estado",
          "fechaEstado",
          "fechaDesde",
          "fechaHasta"
        ],
        "properties": {
          "codigo": {
            "type": [
              "number",
              "null"
            ],
            "description": "Código de la característica."
          },
          "nombre": {
            "type": [
              "string",
              "null"
            ],
            "description": "Nombre de la característica."
          },
          "estado": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "fechaEstado": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "fechaDesde": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "fechaHasta": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          }
        }
      },
      "RtuResultado": {
        "type": "object",
        "description": "Registro tributario de un contribuyente en el RTU.",
        "required": [
          "nit",
          "tipoContribuyente",
          "persona",
          "empresa",
          "representantes",
          "afiliaciones",
          "caracteristicasEspeciales",
          "fechaUltimaActualizacion",
          "fechaConsulta"
        ],
        "properties": {
          "nit": {
            "type": [
              "string",
              "null"
            ],
            "description": "NIT del contribuyente."
          },
          "tipoContribuyente": {
            "$ref": "#/components/schemas/CodigoDescripcion"
          },
          "persona": {
            "description": "Datos de la persona. Presente para personas individuales; `null` para jurídicas.",
            "anyOf": [
              {
                "$ref": "#/components/schemas/PersonaRtu"
              },
              {
                "type": "null"
              }
            ]
          },
          "empresa": {
            "description": "Datos de la empresa, para personas jurídicas; `null` para individuales. Se entrega tal como lo publica la fuente, sin normalizar: su forma todavía no está fijada en este contrato y puede cambiar."
          },
          "representantes": {
            "type": "array",
            "items": {},
            "description": "Representantes del contribuyente. Se entrega tal como lo publica la fuente, sin normalizar: su forma todavía no está fijada en este contrato y puede cambiar. Lista vacía si no hay."
          },
          "afiliaciones": {
            "type": "object",
            "description": "Afiliaciones a ISR y a IVA.",
            "required": [
              "isr",
              "iva"
            ],
            "properties": {
              "isr": {
                "description": "Afiliación a ISR. `null` si no está afiliado.",
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/AfiliacionImpuesto"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "iva": {
                "description": "Afiliación a IVA. `null` si no está afiliado.",
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/AfiliacionImpuesto"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          "caracteristicasEspeciales": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaracteristicaEspecial"
            },
            "description": "Características especiales. Lista vacía si no hay."
          },
          "fechaUltimaActualizacion": {
            "type": [
              "string",
              "null"
            ],
            "description": "Última actualización o ratificación de los datos ante SAT. Fecha tal como la publica SAT. El formato no está normalizado: no asumas uno sin haberlo visto en tu propia integración."
          },
          "fechaConsulta": {
            "type": [
              "string",
              "null"
            ],
            "description": "Momento que la fuente reporta para el dato. No es necesariamente el momento de tu petición: con `actualizado: false` la respuesta puede venir de una copia anterior. Se entrega tal como lo publica la fuente —hoy, en ISO 8601 con zona UTC—, pero el formato no lo normaliza Tributax: trátalo como texto y no lo parsees sin haberlo comprobado en tu propia integración."
          }
        }
      },
      "CuiNitResponse": {
        "type": "object",
        "description": "Respuesta de `POST /catalogos/cui-nit`. Todos los campos están siempre presentes: el que la fuente no informa sale `null`, nunca se omite, y una lista sin elementos sale `[]`. Un `404` significa que la fuente no reportó resultado para los datos enviados. **Un `200` no garantiza que haya datos**: si la fuente responde que la consulta fue exitosa pero no trae ningún campo reconocible, la respuesta es un `200` con `data` presente y todos sus campos en `null`. Comprueba los campos que te importan en vez de deducirlos del status.",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CuiNitResultado"
          }
        }
      },
      "RtuResponse": {
        "type": "object",
        "description": "Respuesta de `POST /catalogos/rtu`. Todos los campos están siempre presentes: el que la fuente no informa sale `null`, nunca se omite, y una lista sin elementos sale `[]`. Un `404` significa que la fuente no reportó resultado para los datos enviados. **Un `200` no garantiza que haya datos**: si la fuente responde que la consulta fue exitosa pero no trae ningún campo reconocible, la respuesta es un `200` con `data` presente y todos sus campos en `null`. Comprueba los campos que te importan en vez de deducirlos del status.",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/RtuResultado"
          }
        }
      },
      "OmisosResponse": {
        "type": "object",
        "description": "Respuesta de `POST /catalogos/omisos`. Todos los campos están siempre presentes: el que la fuente no informa sale `null`, nunca se omite, y una lista sin elementos sale `[]`. Un `404` significa que la fuente no reportó resultado para los datos enviados. **Un `200` no garantiza que haya datos**: si la fuente responde que la consulta fue exitosa pero no trae ningún campo reconocible, la respuesta es un `200` con `data` presente y todos sus campos en `null`. Comprueba los campos que te importan en vez de deducirlos del status.",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/OmisosResultado"
          }
        }
      },
      "CatalogoConsulta": {
        "type": "object",
        "description": "Identificador a consultar. Envía `nit`, `cui`, o los dos. Al menos uno de los dos debe llegar con un valor no vacío: un string vacío (`\"\"`) cuenta como si el campo no se hubiera enviado, y si ninguno de los dos califica la petición se rechaza con 400. Si envías los dos, Tributax no comprueba que correspondan a la misma persona: los reenvía a la fuente tal como llegaron. Envía uno solo si no te consta que sean del mismo contribuyente.",
        "anyOf": [
          {
            "required": [
              "nit"
            ],
            "properties": {
              "nit": {
                "minLength": 1
              }
            }
          },
          {
            "required": [
              "cui"
            ],
            "properties": {
              "cui": {
                "minLength": 1
              }
            }
          }
        ],
        "properties": {
          "nit": {
            "type": "string",
            "description": "NIT del contribuyente a consultar."
          },
          "cui": {
            "type": "string",
            "description": "Código Único de Identificación (CUI) de la persona a consultar."
          },
          "actualizado": {
            "type": "boolean",
            "default": false,
            "description": "Con `false` (el valor por defecto) la respuesta sale de una copia almacenada de la fuente y llega en milisegundos. Con `true` la consulta va a la fuente en ese momento: el dato es el más reciente, pero la respuesta tarda varios segundos. Si la fuente no responde en 30 segundos, la respuesta es `502`. Envía un booleano JSON (`true`/`false`), no un texto."
          }
        }
      }
    }
  }
}
