Facturantes Manual de integración API v1
Entrar al portal

Manual de integración

Consulta de RUC y DNI contra los padrones de SUNAT, tipo de cambio oficial y envío por WhatsApp. Todo con un token, sobre HTTPS y devolviendo JSON.

01 — Empezar

Tu token

Todo va con un token que saca el titular de la cuenta desde el portal. No hay registro público: la cuenta la crea un administrador y entrega el correo y la contraseña de acceso.

Paso 1

Entrar en el portal con el correo y la contraseña que entregó el administrador.

Paso 2

Generar el token en APIs de consulta. Se enseña una sola vez.

Paso 3

Mandarlo en la cabecera Authorization de cada petición.

Cabeceras
Authorization: Bearer 12|aBcD3fGhIjKlMnOpQrStUvWxYz...
Accept: application/json
El token va en tu servidor, nunca en el navegador. Quien lo tenga puede consultar en nombre de la integración, y el consumo se le factura a ella. No lo pongas en JavaScript de una página, ni en una app móvil, ni en un repositorio: llama desde tu backend y que sea él quien hable con nosotros.

Si generas uno nuevo, el anterior deja de valer al instante. Actualiza el sistema que lo estuviera usando antes de generarlo, no después.

02 — Empezar

La primera llamada

Todas las rutas cuelgan de esta base. Es HTTPS y solo HTTPS: una petición por HTTP no se atiende.

URL base
https://portal.api.facturantes.com/api/v1

Prueba con un RUC cualquiera. Si responde 200, ya estás integrado. Elige tu lenguaje:

Petición
curl https://portal.api.facturantes.com/api/v1/padron/ruc/20601030013 \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
03 — Empezar

Qué hacer con cada error

No todos los fallos se tratan igual, y confundirlos es lo que rompe una integración en producción. Hay tres familias:

Familia Códigos Qué hacer
Culpa de la petición 401 · 403 · 422 No reintentes. Repetir da exactamente lo mismo. Corrige el dato o la credencial.
Sin datos 404 No es un fallo. El documento es válido pero no está en el padrón. Trátalo como «sin resultados», no como avería.
Temporal 429 · 503 Reintenta con espera. En el 429, la que diga Retry-After; en el 503, sube el intervalo en cada intento.
El 404 es la trampa clásica. Es tentador tratarlo como error y enseñar «servicio no disponible». No lo es: significa que ese RUC o ese DNI no está en el padrón, que es una respuesta legítima. Un 503, en cambio, sí es que no pudimos averiguarlo — y ahí sí conviene volver a preguntar más tarde.
Reglas

Comunes a todas las llamadas

La respuesta siempre tiene la misma forma

Lo que sale bien viene dentro de data; lo que sale mal, dentro de error. Nunca los dos, así que puedes decidir mirando cuál llegó.

Correcto 200 OK
{
  "data": {
    "razon_social": "REXTIE S.A.C.",
    "estado": "ACTIVO"
  }
}
Con error 422
{
  "error": {
    "code": "datos_invalidos",
    "message": "El RUC no supera la comprobación
                del dígito verificador.",
    "details": { }
  }
}

Decide por code, no por el mensaje

error.code es estable y está pensado para que tu programa lo compare. error.message está escrito para una persona y puede cambiar de redacción sin previo aviso — no lo uses en un if.

Las fechas van en ISO 8601

Siempre AAAA-MM-DD, y las que llevan hora con su huso horario (2026-08-28T09:14:02-05:00). Da igual en qué formato lo publique SUNAT: aquí llega normalizado.

Los campos que no aplican vienen a null

No desaparecen del JSON ni llegan como cadena vacía. Un campo que existe siempre existe; si no hay dato, vale null. Puedes mapear la respuesta sin comprobar si la clave está.

Reglas

Límites de ritmo

Se cuentan por integración, no por IP. Al pasarte recibes un 429 con la cabecera Retry-After diciendo cuántos segundos esperar. Reintentar en bucle mantiene el contador arriba y alarga el bloqueo en vez de acortarlo.

Qué Límite Por qué ese
Consultas al padrón
RUC, DNI, tipo de cambio
120 / minuto Es el de una cuenta nueva. El tuyo lo ves en el panel y se puede subir si lo necesitas.
Ficha web de SUNAT 20 / minuto Cada llamada son varias peticiones contra SUNAT.
Envío por WhatsApp 30 / minuto Lo que quema un número no es el total del día: es la ráfaga.
01 — Endpoint

Consulta de RUC

GET /padron/ruc/{ruc}

Razón social, estado, condición y la dirección desglosada: ubigeo, tipo y nombre de vía, número, interior, distrito, provincia y departamento. Sale de los padrones ya importados, sin salir a la red.

Parámetro Obligatorio Formato
ruc Sí Once dígitos. Se comprueba el dígito verificador antes de consultar.
Respuesta
200 OK
Tiempo típico
~2 ms
Límite
120 / minuto
Petición
curl https://portal.api.facturantes.com/api/v1/padron/ruc/20601030013 \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
Respuesta 200 OK
{
  "data": {
    "razon_social": "REXTIE S.A.C.",
    "numero_documento": "20601030013",
    "nombre_comercial": null,
    "estado": "ACTIVO",
    "condicion": "HABIDO",
    "es_facturable": true,
    "direccion": "CAL. LAS CAMELIAS NRO. 256 INT. 701A URB. JARDIN",
    "ubigeo": "150131",
    "via_tipo": "CAL.",
    "via_nombre": "LAS CAMELIAS",
    "zona_codigo": "URB.",
    "zona_tipo": "JARDIN",
    "numero": "256",
    "interior": "701A",
    "lote": "-",
    "dpto": "LIMA",
    "manzana": "-",
    "kilometro": "-",
    "distrito": "SAN ISIDRO",
    "provincia": "LIMA",
    "departamento": "LIMA",
    "es_agente_retencion": false,
    "es_agente_percepcion": false,
    "es_buen_contribuyente": false,
    "es_exceptuado_percepcion": false,
    "renuncio_exoneracion": false,
    "es_exportador_servicios": false,
    "locales_anexos": null,
    "tipo": null,
    "actividad_economica": null,
    "actividades_economicas": [],
    "numero_trabajadores": null,
    "numero_prestadores_servicio": null,
    "periodo_trabajadores": null,
    "tipo_facturacion": null,
    "tipo_contabilidad": null,
    "comercio_exterior": null,
    "es_emisor_electronico": true,
    "emisor_electronico_desde": "2018-07-30",
    "comprobantes_electronicos": [
      {
        "comprobante": "FACTURA",
        "desde": "2018-07-30"
      },
      {
        "comprobante": "BOLETA DE VENTA",
        "desde": "2019-07-09"
      }
    ],
    "comprobantes_autorizados": [],
    "afiliado_ple_desde": null,
    "fecha_inscripcion": null,
    "fecha_inicio_actividades": null,
    "padrones": [],
    "fuente": "padron",
    "consultado_en": "2026-08-27T20:02:18-05:00",
    "actualizado_en": "2026-08-23T02:15:01-05:00"
  }
}
Da 422 si el dígito verificador no cuadra, y 404 si el RUC es válido pero no está en el padrón.
02 — Endpoint

Consulta de DNI

GET /padron/dni/{dni}

SUNAT construye el RUC de una persona natural como 10 + DNI + dígito verificador, así que la búsqueda es la misma de siempre y resuelve al instante a los 15,4 millones con RUC. A quien no lo tiene se le busca después en una fuente de respaldo, que además devuelve el nombre partido en `nombres`, `apellido_paterno` y `apellido_materno`. Mira `fuente` para saber de dónde salió la respuesta.

Parámetro Obligatorio Formato
dni Sí Ocho dígitos.
Respuesta
200 OK
Tiempo típico
~2 ms
Límite
120 / minuto
Petición
curl https://portal.api.facturantes.com/api/v1/padron/dni/00000006 \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
Respuesta 200 OK
{
  "data": {
    "tipo_documento": "DNI",
    "numero_documento": "00000006",
    "ruc": "10000000065",
    "nombre_completo": "SILVA RIVERA DE RIOS ALICIA",
    "nombres": null,
    "apellido_paterno": null,
    "apellido_materno": null,
    "estado": "ACTIVO",
    "condicion": "HABIDO",
    "es_facturable": true,
    "direccion": null,
    "ubigeo": null,
    "via_tipo": "-",
    "via_nombre": "-",
    "zona_codigo": "-",
    "zona_tipo": "-",
    "numero": "-",
    "interior": "-",
    "lote": "-",
    "dpto": "-",
    "manzana": "-",
    "kilometro": "-",
    "distrito": null,
    "provincia": null,
    "departamento": null,
    "es_agente_retencion": false,
    "es_agente_percepcion": false,
    "es_buen_contribuyente": false,
    "es_exceptuado_percepcion": false,
    "renuncio_exoneracion": false,
    "es_exportador_servicios": false,
    "locales_anexos": null,
    "actividad_economica": null,
    "actividades_economicas": [],
    "numero_trabajadores": null,
    "numero_prestadores_servicio": null,
    "periodo_trabajadores": null,
    "tipo_facturacion": null,
    "tipo_contabilidad": null,
    "comercio_exterior": null,
    "es_emisor_electronico": false,
    "emisor_electronico_desde": null,
    "comprobantes_electronicos": [],
    "comprobantes_autorizados": [],
    "afiliado_ple_desde": null,
    "fecha_inscripcion": null,
    "fecha_inicio_actividades": null,
    "padrones": [],
    "fuente": "padron",
    "consultado_en": "2026-08-27T22:35:16-05:00",
    "actualizado_en": "2026-08-23T00:23:33-05:00"
  }
}
Un 404 aquí no significa que el DNI sea falso: significa que no está en ninguna de las fuentes. La respuesta trae el RUC derivado en los detalles, para distinguirlo. Cuando responde el padrón, `nombres` y los apellidos van a `null`: SUNAT los guarda en una sola cadena y partirlos a ojo sería adivinar —«DE LA CRUZ», «DE LOS RIOS»—. Vienen rellenos solo si contestó una fuente que los separa, y entonces `estado` llega como `SIN RUC`: esa persona no está dada de alta como contribuyente y no se le puede facturar.
03 — Endpoint

Tipo de cambio

GET /tipo-cambio

El que hay que usar al emitir en dólares: SUNAT exige el de la fecha del comprobante, no el del banco ni el del día en que se envía. Sale del fichero que SUNAT publica cada día.

Respuesta
200 OK
Tiempo típico
inmediato
Límite
120 / minuto
Petición
curl https://portal.api.facturantes.com/api/v1/tipo-cambio \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
Respuesta 200 OK
{
  "data": {
    "moneda": "USD",
    "fecha": "2026-08-28",
    "compra": 3.34,
    "venta": 3.348,
    "es_de_hoy": true,
    "consultado_en": "2026-08-28T09:14:02-05:00",
    "fuente": "sunat"
  }
}
SUNAT lo publica a media mañana, así que a primera hora el fichero todavía trae el del día anterior: `es_de_hoy` te lo dice. Si su web no responde se devuelve el último conocido, también con su fecha.
04 — Endpoint

Ficha web de SUNAT

GET /sunat/ruc/{ruc}

Añade lo que el padrón no publica: tipo de contribuyente, actividad económica (CIIU), si es emisor electrónico, padrones especiales y número de trabajadores.

Parámetro Obligatorio Formato
ruc Sí Once dígitos.
Respuesta
200 OK
Tiempo típico
~3 s
Límite
20 / minuto
Petición
curl https://portal.api.facturantes.com/api/v1/sunat/ruc/20601030013 \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
Respuesta 200 OK
{
  "data": {
    "razon_social": "REXTIE S.A.C.",
    "numero_documento": "20601030013",
    "nombre_comercial": "REXTIE",
    "estado": "ACTIVO",
    "condicion": "HABIDO",
    "es_facturable": true,
    "direccion": "CAL.LAS CAMELIAS NRO. 256 INT. 701A URB. JARDIN",
    "ubigeo": null,
    "via_tipo": "-",
    "via_nombre": "-",
    "zona_codigo": "-",
    "zona_tipo": "-",
    "numero": "-",
    "interior": "-",
    "lote": "-",
    "dpto": "LIMA",
    "manzana": "-",
    "kilometro": "-",
    "distrito": "SAN ISIDRO",
    "provincia": "LIMA",
    "departamento": "LIMA",
    "es_agente_retencion": false,
    "es_agente_percepcion": false,
    "es_buen_contribuyente": false,
    "es_exceptuado_percepcion": false,
    "renuncio_exoneracion": false,
    "es_exportador_servicios": false,
    "locales_anexos": null,
    "tipo": "SOCIEDAD ANONIMA CERRADA",
    "actividad_economica": "OTROS TIPOS DE INTERMEDIACIÓN MONETARIA",
    "actividades_economicas": [
      {
        "tipo": "Principal",
        "codigo": "6419",
        "descripcion": "OTROS TIPOS DE INTERMEDIACIÓN MONETARIA"
      }
    ],
    "numero_trabajadores": 42,
    "numero_prestadores_servicio": 7,
    "periodo_trabajadores": "2026-06",
    "tipo_facturacion": "MANUAL/COMPUTARIZADO",
    "tipo_contabilidad": "MANUAL/COMPUTARIZADO",
    "comercio_exterior": "SIN ACTIVIDAD",
    "es_emisor_electronico": true,
    "emisor_electronico_desde": "2018-07-30",
    "comprobantes_electronicos": [
      {
        "comprobante": "FACTURA",
        "desde": "2018-07-30"
      },
      {
        "comprobante": "BOLETA",
        "desde": "2019-07-09"
      }
    ],
    "comprobantes_autorizados": [
      "FACTURA",
      "BOLETA DE VENTA"
    ],
    "afiliado_ple_desde": null,
    "fecha_inscripcion": "2016-02-22",
    "fecha_inicio_actividades": "2016-02-22",
    "padrones": [
      "NINGUNO"
    ],
    "fuente": "sunat",
    "consultado_en": "2026-08-23T00:02:35-05:00",
    "actualizado_en": null
  }
}
Mucho más lento y con el límite más bajo porque cada llamada son varias peticiones contra el servidor de SUNAT. Si su web no responde, contesta el padrón con lo básico en vez de fallar.
WhatsApp

Cómo funciona el envío

Se contrata aparte de las consultas. Si tu integración no lo tiene, estos dos endpoints responden 403 acceso_no_contratado.

Cada número es un dispositivo con su propio token. El token es el emisor: la petición no lleva ningún campo para elegir número, así que no hay nada que equivocar.

Paso 1

En el portal, APIs de WhatsApp → Agregar dispositivo. Nace con su token, visible en su fila.

Paso 2

Vincular saca un QR. Se escanea desde el móvil de ese número; el número no se teclea en ningún sitio.

Paso 3

Mandas con el token de ese dispositivo, no con el de las consultas.

Responde 202, no 200. El mensaje se acepta y sale de una cola, espaciado de los demás. Confirmar un envío que todavía no ha ocurrido sería mentir. Ese espaciado es lo que protege el número: mandar cien seguidos es la forma más rápida de que WhatsApp lo cierre.
WhatsApp

Los dos envíos

Las rutas y los campos van en inglés, al revés que el resto de esta API. Son los del servicio que ya se usaba: un cliente escrito contra aquél cambia la URL y el token y sigue funcionando.

Texto

POST /send/text
Petición
curl -X POST https://portal.api.facturantes.com/api/v1/send/text \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer TU_TOKEN'
Cuerpo
{
  "number": "51987654321",
  "text": "Tu comprobante ya está disponible."
}

Archivos

POST /send/media

El contenido va en base64 dentro del JSON. Uno solo con file; varios con files, hasta cinco.

Un archivo
{
  "number": "51987654321",
  "file": "JVBERi0xLjQK...",
  "filename": "F001-123.pdf",
  "caption": "Adjuntamos tu comprobante."
}
Un comprobante: PDF y XML
{
  "number": "51987654321",
  "caption": "Tu comprobante F001-123",
  "files": [
    { "file": "JVBERi0xLjQK...",
      "filename": "F001-123.pdf" },
    { "file": "PD94bWwgdmVy...",
      "filename": "F001-123.xml" }
  ]
}
Campo Obligatorio Formato
number Sí Destino con código de país y solo dígitos: 51987654321. Sin espacios, guiones ni paréntesis.
file Uno de los dos El contenido en base64, hasta 8 MB ya descodificado. Un data: URI también vale: se le quita el prefijo.
files Uno de los dos Lista de {file, filename}, hasta cinco. No se puede mandar junto con file.
filename Sí Con su extensión: de ahí sale el tipo real del archivo. Un .xml sin extensión llegaría al móvil con icono de PDF y sin abrirse.
filetype No document (por defecto) o image. Una imagen se ve en el chat; un documento sale como tarjeta con su nombre.
caption No Pie del adjunto, hasta 1000 caracteres.
Varios archivos son varios mensajes. WhatsApp no manda dos documentos en un mismo mensaje: salen uno detrás de otro, con el espaciado de la cola entre medias, y el caption va en el primero para que el cliente no lea dos veces lo mismo.
Respuesta, en los dos 202 Accepted
{
  "data": {
    "estado": "encolado",
    "number": "51987654321",
    "desde": "51984342396",
    "mensajes": 2
  }
}
Referencia

Códigos de error

Decide por error.code, que es estable, y no por el mensaje, que está escrito para una persona y puede cambiar de redacción.

HTTP code Qué pasó y qué hacer
401 no_autenticado Falta el token o ya no vale. Comprueba la cabecera Authorization; si lo revocaste, genera otro.
403 cliente_inactivo La integración está pendiente de aprobación o suspendida. No se arregla desde el código.
403 acceso_no_contratado Tu integración no tiene contratada esa familia de API. Escríbenos.
404 ruc_no_encontrado El RUC es válido pero no está en el padrón. No es un fallo: trátalo como «sin datos».
404 dni_no_encontrado El DNI es válido pero no está en el padrón. Un tercio de los adultos no tiene RUC y no aparece en él, así que esto significa «no lo tenemos», no «no existe».
403 token_sin_dispositivo Estás mandando con el token de las consultas. Usa el de la fila del dispositivo.
409 whatsapp_desconectado Ese número está de alta pero no vinculado. No sirve reintentar: hay que escanear el QR desde el portal.
422 datos_invalidos El documento no pasa el dígito verificador, falta un parámetro o el número de destino no lleva código de país. Revisa antes de reintentar: repetir da lo mismo.
429 demasiadas_peticiones Te pasaste del ritmo. Espera los segundos que dice Retry-After en vez de reintentar en bucle.
404 no_encontrado Esa ruta no existe. No es lo mismo que un documento que no está en el padrón: revisa la URL.
503 fuentes_no_disponibles Ninguna fuente respondió. No es lo mismo que un 404: aquí no sabemos si existe, así que conviene reintentar más tarde.
500 error_interno Algo se rompió de nuestro lado. Reintenta más tarde y avísanos si sigue pasando.
Referencia

Lo que más confunde

¿Cada cuánto se actualizan los padrones?

A diario, con lo que publica SUNAT. El campo actualizado_en de cada respuesta dice exactamente cuándo cambió por última vez esa ficha concreta.

¿Sirve el mismo token para consultas y WhatsApp?

No. El de consultas no pertenece a ningún número, así que en WhatsApp da 403 token_sin_dispositivo. Cada dispositivo tiene el suyo y es lo que decide por qué número sale el mensaje.

¿Puedo cambiar el móvil de un dispositivo sin tocar mi código?

Sí. Desvincular suelta el teléfono y deja el token intacto; escaneas el QR con otro móvil y sigues mandando con la misma credencial de siempre.

¿Por qué mi consulta de DNI no encuentra a alguien que existe?

Porque va contra los padrones de SUNAT, y quien no tiene RUC no está en ellos. No es un registro de identidad: es un registro de contribuyentes. Un 404 aquí significa «no lo tenemos», no «no existe».

¿Dónde veo cuánto llevo consumido?

En el portal, dentro de APIs de consulta, con el desglose por endpoint del mes en curso.