Verifica ante el SAT si un RFC está registrado y puede recibir facturas, y coteja nombre y código postal.
Todas las peticiones van al gateway de idoo.dev con tu API key:
API para verificar ante el SAT si un RFC está registrado y es susceptible de recibir facturas, y para cotejar que el nombre o razón social y el código postal coincidan con lo que el SAT tiene registrado. Cada consulta se hace en vivo contra el servicio oficial del SAT: no hay padrones cacheados ni copias locales.
Todas las peticiones van al gateway de idoo.dev con tu API key:
https://idoo.dev/v1/valida-rfc/{accion}
curl -X POST "https://idoo.dev/v1/valida-rfc/validar" \
-H "Authorization: Bearer {tu_api_key}" \
-H "Content-Type: application/json" \
-d '{"rfc": "FCA130603EX5"}'
También se acepta el header X-API-KEY: {tu_api_key}. Las keys se crean en tu panel de idoo.dev.
El ambiente lo determina tu API key, no un parámetro:
| Key | Ambiente | Comportamiento |
|---|---|---|
idoo_sk_test_... |
Sandbox | Devuelve una respuesta simulada al instante, sin consultar al SAT. Gratis e ilimitado: no consume la cuota de tu plan. La forma de la respuesta es idéntica a producción y trae "simulado": true. |
idoo_sk_live_... |
Producción | Consulta real al SAT. Cada consulta descuenta 1 de tu plan. |
Sandbox siempre responde que el RFC es válido, sin importar cuál mandes: sirve para integrar el contrato de la API, no para probar casos de negocio. Los formatos inválidos (422) sí se validan en sandbox.
validar es el único endpoint que descuenta cuota. salud es libre (aplica únicamente al rate limit de tu plan). El header X-Idoo-Cuota-Restante de cada respuesta cobrable te dice cuántas consultas te quedan en el periodo.
Todas las respuestas (éxito o error) usan el mismo sobre JSON:
{
"valid": true,
"status": 200,
"message": "RFC válido, y susceptible de recibir facturas",
"data": { "...": "..." },
"timestamp": "2026-09-09 07:26:07"
}
En los errores, valid es false y se agrega el campo error con un código estable, pensado para que lo compares en tu código — a diferencia de message, que es texto legible y puede cambiar.
status: 200no significa "RFC válido". Significa que la consulta se realizó con éxito. El veredicto está endata.valido.
Tarda típicamente entre 2 y 4 segundos, y puede llegar a 20 cuando se necesitan varios intentos. Configura el timeout de tu cliente en al menos 30 segundos y haz la llamada en segundo plano si tu interfaz no puede esperar. En sandbox la respuesta es inmediata.
| Código | Significado |
|---|---|
| 200 | Consulta realizada (revisa data.valido para el veredicto). |
| 400 | El cuerpo no es un JSON válido. |
| 401 | No se envió API key, o alguien llamó al backend directo sin pasar por el gateway. |
| 402 | Cuota de consultas de tu plan agotada (solo producción). |
| 403 | API key inválida o sin suscripción activa a esta API. |
| 404 | La ruta no existe. |
| 405 | Método HTTP no permitido. |
| 422 | Los datos enviados no son válidos: falta el RFC, o su formato (o el del CP) es incorrecto. |
| 429 | Excediste el rate limit por minuto de tu plan (Retry-After indica cuándo reintentar). |
| 502 | El SAT no respondió, o devolvió algo que no se pudo interpretar. |
| 503 | No se pudo obtener tras varios intentos. |
| 504 | La consulta al SAT excedió el tiempo máximo. |
| Método | Endpoint | Descripción | ¿Descuenta cuota? |
|---|---|---|---|
| POST | validar |
Valida un RFC ante el SAT; opcionalmente coteja nombre y CP. | Sí |
| GET | salud |
Estado del servicio, para monitoreo. | No |
Consulta un RFC ante el SAT.
Body:
{
"rfc": "FON2010129P5",
"nombre": "FONDO DE CULTURA ECONOMICA",
"cp": "14738"
}
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
rfc |
string | Sí | RFC a validar: 12 caracteres para persona moral, 13 para persona física. No distingue mayúsculas. |
nombre |
string | No | Nombre, denominación o razón social a cotejar. |
cp |
string | No | Código postal del domicilio fiscal, 5 dígitos. |
Enviar nombre o cp activa la validación cruzada del SAT: el RFC puede existir y aun así responder que los datos no coinciden. El cotejo del nombre es literal — el SAT compara contra la razón social exacta que tiene registrada, sin régimen de capital (SA DE CV) salvo que así esté inscrita.
Respuesta 200 — solo RFC:
{
"valid": true,
"status": 200,
"message": "RFC válido, y susceptible de recibir facturas",
"data": {
"rfc": "FCA130603EX5",
"nombre": null,
"cp": null,
"resultado": "RFC válido, y susceptible de recibir facturas",
"valido": true,
"simulado": false,
"idoo": { "consumidor_id": 4242, "plan": "Pro", "ambiente": "produccion" }
},
"timestamp": "2026-09-09 07:26:07"
}
Respuesta 200 — con nombre y CP que no coinciden:
{
"data": {
"rfc": "FCA130603EX5",
"nombre": "FONDO DE CULTURA ECONOMICA",
"cp": "14738",
"resultado": "EL Nombre o Razón Social y CP no coinciden con lo registrado en el RFC",
"valido": false,
"simulado": false
},
"message": "EL Nombre o Razón Social y CP no coinciden con lo registrado en el RFC"
}
Campos de data:
| Campo | Tipo | Descripción |
|---|---|---|
rfc |
string | RFC consultado, normalizado a mayúsculas. |
nombre |
string | null | Nombre cotejado, o null si no lo enviaste. |
cp |
string | null | Código postal cotejado, o null si no lo enviaste. |
resultado |
string | Veredicto textual del SAT, tal cual lo devuelve. |
valido |
boolean | true solo si el SAT respondió que el RFC es válido. Si enviaste nombre o cp y no coinciden, es false. |
simulado |
boolean | true cuando la respuesta viene de sandbox y no del SAT. |
idoo |
object | Contexto que el gateway asoció a tu key: consumidor_id, plan y ambiente. Útil para confirmar con qué key estás llamando. |
Errores específicos:
| Código | error |
Cuándo ocurre |
|---|---|---|
| 422 | rfc_requerido |
No enviaste el campo rfc. |
| 422 | rfc_formato_invalido |
El RFC no tiene forma de RFC (12 o 13 caracteres, con la estructura oficial). |
| 422 | cp_formato_invalido |
El código postal no tiene 5 dígitos. |
| 400 | json_invalido |
El cuerpo no es JSON válido. |
| 502 | sat_inalcanzable |
El SAT no respondió. Transitorio: reintenta. |
| 502 | respuesta_inesperada |
El SAT respondió algo que no se pudo interpretar. Transitorio. |
| 503 | no_resuelto |
No hay respuesta del SAT. Transitorio: reintenta. |
| 504 | tiempo_agotado |
La consulta excedió el tiempo máximo. Transitorio. |
Comprueba que el servicio responde. Útil para monitoreo; no consulta al SAT ni descuenta cuota.
curl "https://idoo.dev/v1/valida-rfc/salud" \
-H "Authorization: Bearer {tu_api_key}"
Respuesta 200:
{
"valid": true,
"status": 200,
"message": "Servicio operativo",
"data": {
"servicio": "valida-rfc",
"idoo": { "consumidor_id": 4242, "plan": "Pro", "ambiente": "produccion" }
},
"timestamp": "2026-09-09 07:25:36"
}
idoo_sk_test_... — es gratis e ilimitado. Ahí armas el manejo del sobre JSON y de los errores 422 sin gastar consultas.422 y no descuenta cuota, pero te cuesta un viaje de red; validarlo en tu formulario es mejor experiencia.validar con el RFC solo, o con nombre y cp si necesitas el cotejo completo (por ejemplo, para dar de alta a un cliente que va a recibir facturas).data.valido, no en el status. Un 200 con "valido": false es una respuesta correcta del SAT diciendo que ese RFC no sirve para facturar.502/503/504 con reintentos acotados y espera entre ellos: el SAT se cae seguido. Recuerda que cada reintento descuenta cuota.Todos corren en sandbox y no consumen cuota. Sustituye {tu_api_key} por tu key idoo_sk_test_....
El caso más simple: ¿este RFC puede recibir facturas?
curl -X POST "https://idoo.dev/v1/valida-rfc/validar" \
-H "Authorization: Bearer {tu_api_key}" \
-H "Content-Type: application/json" \
-d '{"rfc": "FCA130603EX5"}'
En producción, data.valido será true si el SAT lo tiene registrado y activo para facturación.
Al dar de alta un cliente conviene verificar que los tres datos que te dio coinciden entre sí; es lo que evita rechazos al timbrar después.
curl -X POST "https://idoo.dev/v1/valida-rfc/validar" \
-H "Authorization: Bearer {tu_api_key}" \
-H "Content-Type: application/json" \
-d '{
"rfc": "FCA130603EX5",
"nombre": "FONDO DE CULTURA ECONOMICA",
"cp": "14738"
}'
Si el SAT responde que no coinciden, el status sigue siendo 200: la consulta funcionó. El problema está en data.valido: false y en data.resultado, que te dice qué falló.
El SAT no siempre responde. Este es el patrón mínimo de reintento, en PHP:
$intentos = 0;
do {
$respuesta = miCliente()->post('validar', ['rfc' => $rfc]);
$codigo = $respuesta['status'];
if ($codigo < 500) {
break; // 200, 422, 400: no tiene caso reintentar
}
$intentos++;
sleep(2 * $intentos); // espera creciente
} while ($intentos < 3);
Tres intentos son suficientes: si el SAT sigue caído, avísale al usuario y guarda el RFC para reintentar más tarde. No lo pongas en un bucle infinito: cada vuelta descuenta cuota.
status como el veredicto. 200 significa "consulté al SAT y esto es lo que dijo". El veredicto está en data.valido.FONDO DE CULTURA ECONOMICA y tú envías FONDO DE CULTURA ECONOMICA SA DE CV, el cotejo falla. Manda el nombre tal como está en la constancia de situación fiscal.422. Ese error es de tus datos, no del SAT: reintentar da exactamente lo mismo.Esta API todavía no tiene reseñas.