Cisma Fact

API de RUC y DNI

Consulta un RUC o un DNI desde tu sistema y rellena los datos del cliente solo con el número. Devuelve razón social, estado, condición y domicilio fiscal para RUC; nombres y apellidos para DNI.

1. Empezar

Son tres pasos:

  1. Pides tus credenciales. Te llegan una API Key y un API Secret.
  2. Pruebas con una llave de sandbox, gratis y con un tope de consultas al mes.
  3. Cambias las credenciales por las de producción y ya estás consultando de verdad.

Dirección base

https://cismafact.alwaysdata.net/api

La misma que para emitir. Las consultas cuelgan de /consultas: /consultas/ruc/{numero}, /consultas/dni/{numero} y /consultas/cuota. Todas son GET y responden en JSON.

2. Credenciales

Van en las cabeceras de cada petición. Las dos son obligatorias.

X-Api-Key: tu_api_key
X-Api-Secret: tu_api_secret
Accept: application/json

El API Secret se enseña una sola vez.

Guárdalo en cuanto lo recibas. No lo pongas en el código de una página web ni en una aplicación de móvil: cualquiera puede leerlo de ahí y gastar tu cuota. Va en tu servidor. Si se te pierde o crees que alguien más lo tiene, pide que te lo cambien.

3. Pruebas

Te damos una llave de sandbox gratuita para que dejes tu integración terminada antes de contratar nada. Consulta los mismos datos reales que producción —la misma SUNAT y el mismo RENIEC—, porque con datos inventados no verías si el servicio te sirve.

Pruébala con RUC y DNI de verdad: los tuyos, los de tus clientes, los que quieras comprobar. No hay números especiales que devuelvan casos preparados.

Lo único distinto de producción es el tope.

La llave de sandbox trae 20 consultas de cada tipo al mes: 20 de RUC y 20 de DNI, que se cuentan por separado. Al agotarse responde 429. Puedes ver lo que te queda en cualquier momento con GET /api/consultas/cuota, y si necesitas más para terminar, nos lo dices.

Cuando la consulta no sale adelante responde 422 y el porqué viene en message, así que conviene leerlo y no solo mirar el código: es el mismo 422 para un número mal escrito (prueba 20000000000, cuyo dígito verificador no cuadra, o un DNI de 7 cifras) que para uno correcto cuyo titular no aparece.

Cuando termines, cambias las dos cabeceras por las de producción. No hay que tocar nada más.

4. Consultar RUC

El número y los datos de este ejemplo son inventados, solo para enseñar la forma de la respuesta. Al probar verás los datos reales del RUC que consultes.

GET https://cismafact.alwaysdata.net/api/consultas/ruc/20000000001

Respuesta

{
  "success": true,
  "data": {
    "valido": true,
    "numero": "20000000001",
    "tipo": "ruc",
    "nombre": "EMPRESA DE EJEMPLO S.A.C.",
    "estado": "ACTIVO",
    "condicion": "HABIDO",
    "direccion": "AV. DE PRUEBA NRO. 100",
    "ubigeo": "150101",
    "departamento": "LIMA",
    "provincia": "LIMA",
    "distrito": "LIMA",
    "fuente": "consultado antes"
  },
  "message": null
}
CampoQué es
nombreRazón social o nombre del contribuyente.
estadoACTIVO, BAJA DE OFICIO, SUSPENSION TEMPORAL… Si no está activo, no puede emitir comprobantes.
condicionHABIDO o NO HABIDO. No habido significa que SUNAT no lo encontró en su domicilio.
direccionDomicilio fiscal.
ubigeoCódigo de 6 dígitos de departamento, provincia y distrito.
fuenteDe dónde salió el dato: proveedor, padron, consultado antes o ninguna. Con ninguna vienen solo el número y el tipo, sin ficha.

Un 200 no siempre trae la ficha

Si el número es correcto pero no se pudo consultar en ese momento, la respuesta sigue siendo 200 con success: true, porque el número vale y no queremos bloquearte por un proveedor caído. Pero llega "fuente": "ninguna", un message explicándolo, y sin nombre ni direccion. Comprueba que el campo existe antes de usarlo, en vez de fiarte solo de success.

5. Consultar DNI

GET https://cismafact.alwaysdata.net/api/consultas/dni/12345678

Respuesta

{
  "success": true,
  "data": {
    "valido": true,
    "numero": "12345678",
    "tipo": "dni",
    "nombre": "JUAN DE PRUEBA EJEMPLO",
    "nombres": "JUAN",
    "apellido_paterno": "DE PRUEBA",
    "apellido_materno": "EJEMPLO",
    "fuente": "consultado antes"
  },
  "message": null
}

Tienes el nombre completo ya armado en nombre y también por partes, por si tu sistema guarda los apellidos en campos separados.

6. Ver tu cuota

Cuánto llevas gastado y cuánto te queda. No gasta cuota.

GET https://cismafact.alwaysdata.net/api/consultas/cuota
{
  "llave": "Producción",
  "entorno": "produccion",
  "plan": "Pro",
  "expira_en": null,
  "renueva": "2026-10-01",
  "servicios": [
    { "servicio": "ruc", "nombre": "Consulta RUC", "disponible": true,
      "limite_mensual": 10000, "usadas": 1, "restantes": 9999 },
    { "servicio": "dni", "nombre": "Consulta DNI", "disponible": true,
      "limite_mensual": 2000, "usadas": 1, "restantes": 1999 }
  ]
}

Los límites del ejemplo son ilustrativos: los tuyos son los de tu plan, y salen aquí.

7. Errores

Cuando algo va mal, success es false y message explica qué pasó, en castellano. Puedes enseñárselo a tu usuario tal cual.

CódigoQué pasóQué hacer
401 Faltan las cabeceras o las credenciales no valen. Revisa que mandas las dos y que no llevan espacios de más.
403 La llave está bloqueada, venció, o tu plan no incluye ese servicio. El mensaje dice cuál de los tres. Escríbenos.
422 El número no es válido: no tiene los dígitos que toca, o el dígito verificador no cuadra. Nada: no gasta cuota. Enséñale el mensaje a tu usuario.
429 Se acabó tu cuota del mes, o vas demasiado rápido. Espera al día 1, sube de plan, o baja el ritmo.
503 Ese servicio está fuera de servicio un rato. Reintenta en unos minutos. No gasta cuota.

Ejemplo

{
  "success": false,
  "data": null,
  "message": "El RUC no es válido: el dígito verificador no cuadra."
}

8. Límites

  • 30 peticiones por minuto. Es aparte de tu cuota mensual: evita que te la gastes de golpe por un fallo en tu código.
  • Cuota mensual según tu plan, contada por separado para RUC y para DNI.
  • Lo que falla no gasta cuota. Un número mal escrito o un servicio caído no te cuestan nada.
  • La cuota se reinicia el día 1 de cada mes. No se acumula lo que no gastaste.

9. Ejemplos

curl

curl -H "X-Api-Key: tu_api_key" \
     -H "X-Api-Secret: tu_api_secret" \
     -H "Accept: application/json" \
     https://cismafact.alwaysdata.net/api/consultas/ruc/20000000001

PHP

<?php

function consultarRuc(string $ruc): ?array
{
    $ch = curl_init('https://cismafact.alwaysdata.net/api/consultas/ruc/' . $ruc);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'X-Api-Key: ' . getenv('CISMA_API_KEY'),
            'X-Api-Secret: ' . getenv('CISMA_API_SECRET'),
            'Accept: application/json',
        ],
    ]);

    $cuerpo = json_decode(curl_exec($ch), true);
    curl_close($ch);

    // Un RUC que no existe no es un fallo del programa: devuelve null y que
    // el formulario avise, en vez de reventar.
    return ($cuerpo['success'] ?? false) ? $cuerpo['data'] : null;
}

$empresa = consultarRuc('20000000001');
echo $empresa['nombre'] ?? 'No encontrado';

Python

import os, requests

CABECERAS = {
    "X-Api-Key": os.environ["CISMA_API_KEY"],
    "X-Api-Secret": os.environ["CISMA_API_SECRET"],
    "Accept": "application/json",
}

def consultar_ruc(ruc):
    r = requests.get(f"https://cismafact.alwaysdata.net/api/consultas/ruc/{ruc}",
                     headers=CABECERAS, timeout=15)
    cuerpo = r.json()
    return cuerpo["data"] if cuerpo.get("success") else None

empresa = consultar_ruc("20000000001")
print(empresa["nombre"] if empresa else "No encontrado")

JavaScript / Node.js

// Desde el servidor, nunca desde el navegador: ahi el secreto queda a la vista.
const cabeceras = {
  'X-Api-Key': process.env.CISMA_API_KEY,
  'X-Api-Secret': process.env.CISMA_API_SECRET,
  'Accept': 'application/json',
};

async function consultarRuc(ruc) {
  const r = await fetch(`https://cismafact.alwaysdata.net/api/consultas/ruc/${ruc}`, { headers: cabeceras });
  const cuerpo = await r.json();
  return cuerpo.success ? cuerpo.data : null;
}

const empresa = await consultarRuc('20000000001');
console.log(empresa?.nombre ?? 'No encontrado');

¿Lo quieres probar?

Escríbenos y te damos credenciales de prueba para que dejes tu integración lista antes de contratar nada.