Catálogos — CUI/NIT, RTU y omisos
POST /catalogos/cui-nit
POST /catalogos/rtu
POST /catalogos/omisos
Tres consultas de contribuyente que comparten el mismo catálogo de errores y el mismo límite por minuto. Se habilitan por separado en tu integración: tener una activa no habilita las otras dos.
En esta página, «la fuente» es el servicio de datos que Tributax consulta por ti para resolver estos tres catálogos; la información se origina en los registros de SAT. Cuando decimos «la fuente no lo informó» queremos decir que el dato no vino en esa respuesta, sin distinguir si SAT no lo tiene o si no se publicó. No necesitas contratar nada con ese servicio ni conocerlo: tu contrato es con Tributax, y la forma de la respuesta no cambia si cambiamos de fuente.
Requisitos previos
- Credenciales de integración válidas. Estas tres rutas no usan
x-user-nit: no se opera por cuenta de ningún contribuyente, se consulta un registro. Si tu cliente lo envía de todos modos, no cambia nada: estas rutas se resuelven antes de que exista la noción de contribuyente. - La bandera de cada catálogo, activa en tu integración. La activa un administrador de
Tributax; no es algo que puedas activar tú. Sin ella,
403. - Saldo disponible en tu integración. Cada consulta que se resuelve bien descuenta de un saldo
prepago. Si se agota, las tres consultas responden
402hasta que se recargue — ver Saldo y cobro.
| Consulta | Endpoint | Qué resuelve |
|---|---|---|
| CUI/NIT | POST /catalogos/cui-nit | La correspondencia entre el CUI y el NIT de un contribuyente |
| RTU | POST /catalogos/rtu | El registro del contribuyente en el Registro Tributario Unificado |
| Omisos | POST /catalogos/omisos | Si el contribuyente está listado como omiso (declaraciones pendientes) |
:::info No es el mismo endpoint que /rtu/nits
POST /catalogos/rtu es una consulta distinta de RTU por NIT. Coinciden en el
nombre, no en el contrato:
POST /rtu/nits | POST /catalogos/rtu | |
|---|---|---|
| Cuántos por petición | hasta 50 NIT | uno |
| Identificador | solo NIT | NIT o CUI |
| Forma de la respuesta | como la publica la fuente | contrato propio de Tributax |
| Clave de error | error | message |
| Habilitación | is_rtu_enabled | is_rtu_v2_enabled |
| Límite | 50 por minuto, propio | 30 por minuto, compartido con CUI/NIT y Omisos |
Cuál usar: si necesitas resolver muchos NIT de una pasada, POST /rtu/nits. Si necesitas el
registro completo de un contribuyente —régimen, afiliaciones, obligaciones— con una forma de
respuesta estable, POST /catalogos/rtu.
Cuando pidas la habilitación, nombra la ruta exacta, no «RTU»: son dos banderas distintas y
activan cosas distintas. El v2 de is_rtu_v2_enabled es un nombre interno heredado; no significa
que exista una versión 2 de esta API, que no lleva versión.
:::
Petición
curl -sS -X POST 'https://dev.api.tributax.app/catalogos/cui-nit' \
-H 'content-type: application/json' \
-H 'x-integracion-login: <NOMBRE_INTEGRACION>' \
-H 'x-integracion-token: <TOKEN_INTEGRACION>' \
-d '{"nit":"<NIT>"}'
Los tres catálogos usan las mismas credenciales y los mismos identificadores; solo cambia la URL de
la tabla de arriba. date_of_birth es la única diferencia: solo lo lee /catalogos/rtu.
| Campo | Tipo | ¿Obligatorio? | Notas |
|---|---|---|---|
nit | string | uno de los dos | No vacío. |
cui | string | uno de los dos | No vacío. |
actualizado | boolean | no | false por defecto. Ver Datos al momento. |
date_of_birth | string YYYY-MM-DD | no, y solo en /catalogos/rtu | Fecha de nacimiento de la persona individual, o de constitución de la jurídica. La fuente la pide solo cuando no tiene copia del registro. Los otros dos catálogos la descartan. Tributax no valida su formato: la reenvía tal como llega. |
Envía nit, cui, o ambos — con que uno llegue como texto no vacío basta. Si ninguno cumple:
400 {"message":"Envia un NIT o un CUI para consultar."}.
Si envías los dos, Tributax no comprueba que correspondan a la misma persona: los reenvía a la fuente tal como llegaron y es ella la que decide qué hacer. Envía uno solo si no te consta que sean del mismo contribuyente.
Datos al momento: actualizado
Por defecto la respuesta sale de una copia que mantiene la fuente. Con "actualizado": true la
consulta va a la fuente en ese momento: el dato es el más reciente, pero la respuesta tarda
sensiblemente más.
- Úsalo cuando necesites confirmar un cambio reciente —un contribuyente que acaba de actualizar su RTU o de ponerse al día con SAT—, no como valor por defecto de tu integración.
- Para saber qué tan vieja es la copia, mira
fechaConsulta, que trae el momento que la fuente reporta para ese dato. - Toda consulta, con
actualizadoo sin él, tiene un tope de 30 segundos; pasado ese tiempo la respuesta es502. Como contruela espera se acerca a ese tope, configura el timeout de tu cliente por encima de 30 segundos o vas a cortar la conexión antes que nosotros y no vas a ver el502. - Envía un booleano JSON (
true/false), no un texto:"true"entre comillas no es parte del contrato.
Respuestas
Los tres catálogos responden 200 con el registro dentro de data.
:::caution 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. No se distingue de un
registro real cuyos atributos vinieran todos vacíos. Comprueba los campos que te importan en vez de
deducirlos del status.
El 404, por su parte, significa que la fuente no reportó resultado para los datos enviados.
:::
La forma de data es un contrato de Tributax, el mismo sin importar cómo publique sus datos la
fuente, y sigue cuatro reglas:
- Nombres en camelCase.
- Todos los campos están siempre presentes. El que la fuente no informa sale
null, nunca se omite. Una lista sin elementos sale[], nuncanull. - La mayoría de los valores catalogados por SAT salen como
{ "codigo", "descripcion" }. Si SAT no informa el valor, los dos campos salennully el objeto sigue ahí.codigollega como número (1383) o como texto ("818") según el catálogo: normaliza conString(codigo)antes de comparar y no lo guardes en una columna numérica, porque los códigos con ceros a la izquierda se rompen. Hay excepciones a esta forma:actividadesEconomicas[]usa{ ciiu, nombre, clasificacion };marcas[]ycaracteristicasEspeciales[]usan{ codigo, nombre }; ymarcas[].estadoes un código numérico suelto, no un objeto. Genera tu modelo desde el esquema, no desde esta regla. nullno esfalse. Un booleano ennullsignifica que la fuente no lo informó. En omisos en particular, no lo trates como «sin incumplimientos».
Un solo formato de fecha está garantizado por este contrato: fechaNacimiento, en
YYYY-MM-DD — Tributax la convierte. Todas las demás, incluida fechaConsulta, se entregan
tal como las publica la fuente: trátalas como texto, no las parsees ni las uses para calcular sin
haber comprobado su formato en tu propia integración.
fechaConsulta te dice qué tan fresco es el dato, no cuándo llamaste: es el momento que la fuente
reporta para ese dato. Con "actualizado": true es prácticamente el instante de tu petición; con
el valor por defecto puede ser anterior. Hoy llega en ISO 8601 con zona UTC, y Guatemala es UTC−6
sin horario de verano: 2026-09-15T02:25:12Z es el 14 de septiembre en Guatemala, no el 15.
El esquema completo, campo por campo, está en la referencia de la API.
CUI/NIT
{
"data": {
"cui": "<CUI>",
"nit": "<NIT>",
"nombre": "<NOMBRES>, <APELLIDOS>",
"tipoPersona": "individual",
"fechaConsulta": "2026-09-15T15:06:28Z"
}
}
| Campo | Tipo | Qué es |
|---|---|---|
cui | string | null | CUI del contribuyente |
nit | string | null | NIT del contribuyente |
nombre | string | null | Nombre completo en un solo campo, como lo registra la fuente. No lo partas para deducir nombres y apellidos: la puntuación la pone la fuente y no es parte de este contrato. Si los necesitas separados, usa RTU |
tipoPersona | "individual" | "juridica" | null | null si la fuente no lo informa o informa un valor que no se reconoce: en ese caso no deduzcas ninguno de los dos |
fechaConsulta | string | null | Momento que la fuente reporta para el dato, con el formato que ella publica |
Omisos
{
"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"
}
}
| Campo | Tipo | Qué es |
|---|---|---|
tieneIncumplimientos | boolean | null | Si SAT registra obligaciones sin presentar. Es el motivo de la consulta. |
tieneProcesoCoactivo | boolean | null | Si SAT registra un proceso de cobro coactivo |
incumplimientos | string[] | Detalle, como texto de SAT. [] cuando no hay |
nit, nombre, nombreComercial | string | null | Identificación del contribuyente. nombre viene en un solo campo; no lo partas por la coma |
cui | string | null | Tal como lo publica la fuente: puede venir con espacios entre grupos de dígitos. El cui de CUI/NIT no trae esa advertencia, así que si vas a cruzar los dos, quita los espacios de ambos lados antes de comparar |
versionDpi, estadoContribuyente, tipoAfiliacion, regimen | string | null | Datos de afiliación, como texto de SAT |
fechaAfiliacion | string | null | Como la publica SAT |
domicilioFiscal | objeto | departamento, municipio, direccion, telefono; cada uno string | null. El objeto siempre está |
establecimientos | array | Sin normalizar, ver Campos sin forma fija |
fechaConsulta | string | null | Momento que la fuente reporta para el dato, con el formato que ella publica |
RTU
El ejemplo está recortado a lo representativo; la respuesta real trae todos los campos del
esquema, con null donde no hay dato.
{
"data": {
"nit": "<NIT>",
"tipoContribuyente": { "codigo": "1", "descripcion": "PERSONA/NEGOCIO" },
"persona": {
"primerNombre": "<PRIMER_NOMBRE>",
"primerApellido": "<PRIMER_APELLIDO>",
"dpi": "<CUI>",
"fechaNacimiento": "1990-01-31",
"genero": { "codigo": 1383, "descripcion": "MASCULINO" },
"sectorEconomico": {
"codigo": 750,
"descripcion": "SERVICIOS",
"estado": { "codigo": null, "descripcion": null },
"fechaInicio": null
},
"actividadesEconomicas": [
{ "ciiu": "8411.40", "nombre": "ADMINISTRACION PUBLICA", "clasificacion": null }
]
},
"empresa": null,
"representantes": [],
"afiliaciones": {
"isr": null,
"iva": {
"impuesto": { "codigo": "11", "descripcion": "IMPUESTO AL VALOR AGREGADO" },
"regimen": { "codigo": "818", "descripcion": "PEQUEÑO CONTRIBUYENTE" },
"exento": false,
"obligaciones": [
{
"nombre": "IVA PEQUEÑO CONTRIBUYENTE",
"generaEtiquetaOmiso": true,
"estado": { "codigo": null, "descripcion": null }
}
]
}
},
"caracteristicasEspeciales": [
{
"codigo": 2432,
"nombre": "EMISOR DE FACTURA ELECTRÓNICA",
"estado": { "codigo": null, "descripcion": null }
}
],
"fechaUltimaActualizacion": null,
"fechaConsulta": "2026-09-15T15:19:56Z"
}
}
| Campo | Tipo | Qué es |
|---|---|---|
nit | string | null | NIT del contribuyente |
tipoContribuyente | código SAT | Tipo de contribuyente, según SAT |
persona | objeto | null | Viene lleno para personas individuales. Nombres y apellidos por separado, dpi, serieDpi, versionDpi, fechaNacimiento (YYYY-MM-DD), fechaVencimientoDpi, genero, estadoCivil, nacionalidad, tipoDocumento, estado, sectorEconomico, actividadesEconomicas[], marcas[], participacionGremial, participacionEmpresarial |
empresa | objeto | null | Viene lleno para personas jurídicas. Sin normalizar, ver Campos sin forma fija |
representantes | array | Sin normalizar, ver Campos sin forma fija |
afiliaciones.isr, afiliaciones.iva | objeto | null | null si el contribuyente no está afiliado a ese impuesto. Cada uno trae impuesto, regimen, tipoContribuyente, periodoImpositivo, formaCalculo, estatusAfiliacion, tipoRenta (solo ISR), tipoEstablecimiento (solo IVA), exento, fechaDesde y obligaciones[] |
afiliaciones.*.regimen | código SAT | El régimen, con el mismo nombre en ISR y en IVA |
afiliaciones.*.obligaciones[] | array | nombre, periodo, formulario, generaEtiquetaOmiso (si incumplirla deja al contribuyente marcado como omiso), requerida, estado |
caracteristicasEspeciales | array | Por ejemplo, emisor de factura electrónica: codigo, nombre, estado, fechaEstado, fechaDesde, fechaHasta |
fechaUltimaActualizacion | string | null | Última actualización o ratificación de los datos ante SAT, como la publica SAT |
fechaConsulta | string | null | Momento que la fuente reporta para el dato, con el formato que ella publica |
Dos campos de RTU se salen de la forma general: marcas[].estado es un código numérico suelto, no
un objeto { codigo, descripcion } como los demás estado; y actividadesEconomicas[] usa
{ ciiu, nombre, clasificacion }.
Persona individual o jurídica
persona viene lleno para individuales y empresa para jurídicas. Pero la regla general de este
contrato es que un campo que la fuente no informa sale null, así que persona: null no prueba
por sí solo que sea jurídica: puede ser que el bloque no haya venido. Si tu lógica depende de la
distinción, exige que el bloque contrario venga lleno (persona === null && empresa !== null ⇒
jurídica) y trata «los dos en null» como no determinado, no como un valor por defecto.
Campos sin forma fija
empresa y representantes en RTU, y establecimientos en omisos, se entregan tal como los
publica la fuente, sin normalizar. Quedan fuera de las garantías del resto de este contrato: su
forma todavía no está fijada y puede cambiar sin anuncio previo. Mientras tanto, guárdalos como
JSON opaco en vez de mapearlos a columnas tipadas, y no ramifiques tu lógica de negocio por sus
campos. Si necesitas un dato estable de ahí, escríbenos desde Contacto y lo
incorporamos al contrato normalizado.
:::caution El sobre es distinto al de RENAP y RTU por NIT
Estos tres catálogos responden {"data": …} y sus errores con la clave message, como el resto de
la API. RENAP y RTU por NIT responden sus errores con la clave
error y traen además success y responseCode dentro del cuerpo. Acá no existe
responseCode: el status HTTP es tu única señal de éxito. Si reusas el parseo de esas dos
consultas, vas a leer claves que no están.
:::
Errores
| Situación | Status | Cuerpo |
|---|---|---|
Ni nit ni cui llegaron utilizables | 400 | {"message":"Envia un NIT o un CUI para consultar."} |
| La fuente rechazó los datos de la consulta | 400 | {"message":"Los datos de la consulta no son validos."} |
| Las credenciales de integración no corresponden a ninguna integración | 401 | {"message":"Integración no encontrada con estas credenciales."} |
| La fuente rechazó la autenticación de la consulta | 401 | {"message":"No fue posible autenticar la consulta. Escribe a soporte."} |
| El saldo de tu integración se agotó | 402 | {"message":"Tu integracion no tiene saldo disponible. Recarga para seguir consultando."} |
| El servicio de consultas no tiene saldo disponible | 402 | {"message":"El servicio de consultas no tiene saldo disponible. Escribe a soporte."} |
| Sin credenciales de integración | 403 | {"message":"Se requieren credenciales de integracion."} |
| Este catálogo no está habilitado en tu integración | 403 | {"message":"Esta consulta no esta habilitada para tu integracion."} |
| La fuente niega el acceso a esta consulta | 403 | {"message":"Esta consulta no esta habilitada. Escribe a soporte."} |
| No hay registro para los datos enviados | 404 | {"message":"No encontramos informacion para los datos enviados."} |
| Más de 30 consultas por minuto en tu integración | 429 | {"message":"Demasiadas consultas seguidas. Intenta en un minuto."} |
| La fuente está limitando las consultas | 429 | {"message":"Demasiadas consultas seguidas. Intenta de nuevo en unos minutos."} |
| Fallo no controlado de la API | 500 | El mensaje varía; no lo uses como condición |
| La fuente no respondió | 502 | {"message":"El servicio de consultas no esta disponible en este momento."} |
Los mensajes van sin tildes tal como los emite la API — no es un error de esta página, cópialos tal cual si los vas a mostrar.
Ramifica tu código por el status, no por el texto. El texto de un mensaje puede cambiar sin aviso previo (Versionado). En los tres pares de abajo el mensaje es hoy el único indicio de cuál de las dos causas ocurrió: úsalo para decidir a quién escribir o qué registrar en tu log, no como la condición que dispara un reintento automático.
- Dos
401, con causas opuestas. Si el mensaje habla de la integración, el problema es tuyo: revisa tus credenciales y el entorno contra el que estás pegando. También sale así si envías solo uno de los dos headers. Si dice "No fue posible autenticar la consulta", tus credenciales están bien y falló la autenticación contra la fuente: escribe a soporte, no rotes nada. - Dos
402de "sin saldo". Uno es el saldo prepago de tu integración, que se recarga escribiendo a soporte; el otro es del servicio de consultas, del lado de Tributax. En los dos casos la consulta no se ejecutó y no se te cobró. - Dos
403de "no habilitada". Uno es de Tributax ("...para tu integracion."— tu integración no tiene la bandera de este catálogo) y otro es de la fuente ("...Escribe a soporte."— la fuente le negó el acceso a la consulta). El primero lo resuelve un administrador de Tributax activando tu bandera; el segundo requiere escribir a soporte. - Dos
429de "demasiadas consultas". Uno es el límite de Tributax (30 por minuto, "Intenta en un minuto") y otro es el límite propio de la fuente ("Intenta de nuevo en unos minutos"). Ninguno traeRetry-After.
Qué hacer ante un 502
Un 502 quiere decir que la fuente no respondió o falló de su lado. Tu consulta no se resolvió,
no se te cobró, y reintentar es seguro: no duplica nada.
- Reintenta con retroceso exponencial, igual que con un
429(Entornos y límites). - Cada intento gasta del límite de 30 por minuto compartido entre los tres catálogos, y del global de 100 por 15 minutos. Tres reintentos seguidos consumen cuatro de esos 30.
- El tope antes del
502es de 30 segundos. Pon el timeout de tu cliente por encima de ese valor, sobre todo si envías"actualizado": true.
Un 404 es distinto: ahí la fuente sí respondió. Cubre tanto que no haya registro para los datos
enviados como que la fuente haya marcado la consulta como fallida, y los dos casos comparten status
y mensaje, así que no se distinguen desde tu lado. Tratalo como «no tengo el dato ahora», no como
«este contribuyente no existe»: si el identificador te consta bueno, reintenta más tarde antes de
darlo por inexistente. Los datos rechazados por la fuente, en cambio, son 400.
Límite: 30 por minuto, compartido entre los tres
Los tres catálogos gastan del mismo contador por integración — no hay 30 para CUI/NIT más 30
para RTU más 30 para Omisos. Agotar el minuto consultando cui-nit deja sin cupo a rtu y a
omisos hasta que la ventana se reinicie.
Este límite se suma al global de 100 por 15 minutos; ambos aplican a la vez.
La ventana se reinicia a más tardar 60 s después de la primera consulta del minuto. No hay
cabecera Retry-After. El contador vive en memoria del proceso: el límite nominal no es una
garantía de capacidad.
Al excederlo: 429 {"message":"Demasiadas consultas seguidas. Intenta en un minuto."}.
En estas rutas puedes recibir tres 429 distintos: el de los catálogos, el de la fuente y el
global por IP, que responde con el cuerpo por defecto del limitador y no necesariamente es JSON.
Comprueba el Content-Type antes de parsear.
Saldo y cobro
Cada consulta que se resuelve bien descuenta de un saldo prepago por integración, según la tarifa vigente de tu integración.
- Solo se cobran las consultas que se resolvieron bien. Un
502, un429, un404o un error de la fuente no descuentan saldo. - Si el saldo llega a cero, las tres consultas responden
402con{"message":"Tu integracion no tiene saldo disponible. Recarga para seguir consultando."}, y la consulta ni siquiera llega a la fuente. - No hay endpoint para consultar tu saldo ni para recargarlo. Lo administra Tributax: escríbenos desde Contacto para recargar, o para acordar un aviso antes de que se agote.
Cada consulta queda registrada
De cada consulta que llega a la fuente se registra la integración, el catálogo consultado, el status, el tiempo de respuesta y el identificador que enviaste (NIT o CUI) — incluidas las que la fuente responde con error. Sirve para auditoría.
No queda registro de los rechazos anteriores a la consulta: 400 sin NIT ni CUI, credenciales
ausentes o inválidas, catálogo no habilitado, saldo agotado y el límite de 30 por minuto.
Para habilitar cualquiera de estos tres catálogos en tu integración, escríbenos desde Contacto.
📄 Estado de verificación: leído del código del backend. No se ha ejercido contra el entorno desplegado en esta entrega.