- Blog
- Integración
Caché de consultas RUC y DNI: qué guardar y por cuánto tiempo
Una caché de consultas RUC y DNI ahorra créditos y acelera tu sistema: qué datos cambian, qué TTL usar, caché en base de datos o Redis e invalidación.
Un ERP típico consulta el mismo RUC muchas veces: al crear el cliente, al abrir el formulario de la factura, al guardarla, al emitirla, al generar la guía de remisión. Cada consulta cuesta un crédito y unos cientos de milisegundos. Multiplica eso por cientos de clientes recurrentes y tienes miles de llamadas al mes que devuelven lo mismo que la anterior.
Una caché bien diseñada elimina casi todas esas llamadas sin perder lo importante: enterarte a tiempo de que un proveedor pasó a NO HABIDO o de que un cliente dio de baja su RUC. En este artículo vas a ver qué datos cambian y cuáles casi nunca, qué tiempo de vida (TTL) conviene para cada tipo de dato, cómo implementar la caché en una base de datos o en Redis, cuándo invalidarla antes de tiempo y cómo estimar el ahorro en créditos.
Por qué cachear consultas de RUC y DNI
Hay tres motivos, y el dinero es solo uno de ellos.
Velocidad. Una lectura de tu base de datos o de Redis tarda milisegundos; una llamada a cualquier API externa tarda cientos. En un formulario que autocompleta la razón social mientras el usuario escribe, esa diferencia se nota.
Costo. Cada consulta exitosa a la API de RUC o a la de DNI consume un crédito. Si el 80 % de tus consultas son repeticiones de algo que ya preguntaste esta semana, estás pagando cinco veces por el mismo dato.
Resiliencia. Si la API no responde unos minutos, la caché te permite seguir operando con el último dato conocido, marcado como tal, en vez de bloquear la emisión. Es el complemento natural del manejo de errores y reintentos.
Qué datos cambian y cuáles casi nunca
El error más común es tratar toda la respuesta como un bloque con un único TTL. En realidad, dentro de una misma respuesta conviven datos de identidad, que casi no cambian, y datos de situación, que pueden cambiar cualquier día.
| Dato | Cambia | Con qué frecuencia |
|---|---|---|
| Nombres y apellidos por DNI | Casi nunca | Solo por rectificación |
| Nombres por carnet de extranjería | Casi nunca | Solo por rectificación |
| Razón social | Rara vez | Cambio de denominación, fusiones |
| Domicilio fiscal y ubigeo | A veces | Mudanzas, cambio de local |
| Estado del RUC | Cualquier día | Bajas, suspensiones, reactivaciones |
| Condición del domicilio | Cualquier día | Verificaciones de SUNAT |
| Representantes legales | A veces | Cambios de gerencia o de poderes |
| Trabajadores por periodo | Cada mes | Un periodo nuevo por mes |
| Tipo de cambio de una fecha | Nunca, una vez publicado | Es un dato histórico |
| Catálogo de ubigeo | Casi nunca | Creación de un distrito nuevo |
El estado y la condición del RUC son los datos críticos. Facturar a un contribuyente en BAJA o comprar a uno NO HABIDO tiene consecuencias tributarias reales, que explicamos en qué significan ACTIVO y HABIDO. Por eso esos dos campos merecen un TTL corto, mientras que la razón social puede vivir en tu caché semanas sin riesgo.
Con el DNI pasa lo contrario: el dato que te interesa (nombres y apellidos) es estable, así que una vez verificado puedes conservarlo mientras dure la relación con esa persona. El límite ahí no lo pone la volatilidad del dato sino la Ley 29733: guarda solo lo que necesitas y para la finalidad que informaste. En protección de datos personales para desarrolladores está el detalle.
TTL recomendados por tipo de dato
Estos valores son una recomendación práctica, no una norma. Ajústalos según cuánto te cuesta equivocarte: un sistema que emite facturas a terceros necesita datos más frescos que un CRM que solo muestra nombres.
| Dato | TTL sugerido | Comentario |
|---|---|---|
| Estado y condición del RUC | 24 horas | Revalidar en vivo antes de emitir |
| Razón social, dirección, ubigeo | 30 días | Misma fila que el estado, otro criterio de frescura |
| Nombres por DNI o carnet | 90 días o mientras dure la relación | Permitir corrección manual |
| Representantes legales | 7 a 30 días | Más corto si firmas contratos |
| Trabajadores por RUC | 30 días | Aparece un periodo nuevo cada mes |
| Tipo de cambio de fechas pasadas | Sin vencimiento | Nunca cambia una vez publicado |
| Catálogo de ubigeo | Sin vencimiento | Recargar el catálogo cada cierto tiempo |
| Búsquedas por razón social | 1 hora o no cachear | Demasiadas variantes de texto |
| Respuesta 404 (no existe) | 1 hora | Caché negativa |
Dos notas. La caché negativa (guardar que un RUC no existe) sirve para velocidad y para no golpear la API en bucle, no para ahorrar dinero, porque en endpoint.pe las consultas sin resultado no se cobran. Y el tipo de cambio es el caso ideal de caché: una vez que guardaste el valor del 9 de octubre de 2026 (compra 3.708, venta 3.712), jamás tienes que volver a pedirlo. El histórico completo va en tu propia tabla, como en automatizar el tipo de cambio diario.
Caché en base de datos o en Redis
Las dos opciones funcionan, y muchas veces conviene combinarlas.
Una tabla en tu base de datos. Guardas el RUC como clave, la respuesta completa en una columna JSON y la fecha de consulta. Es persistente, puedes hacer reportes con SQL y, si conservas el historial en vez de sobrescribir, tienes evidencia de que el cliente estaba ACTIVO y HABIDO el día que le facturaste. Esa evidencia vale mucho ante una revisión.
Redis. Clave y valor con TTL incorporado: escribes con SET clave valor EX segundos y Redis borra lo vencido. Es muy rápido y muy simple, pero volátil y sin historial. Ideal como capa caliente delante de la base de datos, o como única caché en un servicio que no factura (por ejemplo, un buscador).
Un ejemplo en Python con Redis, donde el valor vacío representa un 404:
import json
import os
import redis
import requests
TOKEN = os.environ["ENDPOINT_TOKEN"]
cache = redis.Redis.from_url(os.environ["REDIS_URL"])
TTL_RUC = 24 * 3600 # estado y condición: un día
TTL_NO_EXISTE = 3600 # caché negativa: una hora
def consultar_ruc(ruc: str) -> dict | None:
clave = f"ruc:{ruc}"
guardado = cache.get(clave)
if guardado is not None:
dato = json.loads(guardado)
return dato or None # un objeto vacío significa "no existe"
r = requests.get(
f"https://api.endpoint.pe/v1/ruc/{ruc}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=10,
)
if r.status_code == 404:
cache.set(clave, "{}", ex=TTL_NO_EXISTE)
return None
r.raise_for_status()
dato = r.json()["data"]
cache.set(clave, json.dumps(dato), ex=TTL_RUC)
return dato
Y el mismo patrón en JavaScript con una tabla SQL, con la opción de forzar la actualización:
const TTL_MS = 24 * 60 * 60 * 1000;
async function consultarRucConCache(ruc, forzar = false) {
const fila = await db.get(
'SELECT payload, consultado_en FROM consultas_ruc WHERE ruc = ?',
[ruc],
);
const edad = fila ? Date.now() - new Date(fila.consultado_en).getTime() : Infinity;
if (fila && edad < TTL_MS && !forzar) {
return JSON.parse(fila.payload);
}
const dato = await consultarRuc(ruc); // la función con reintentos
await db.run(
`INSERT INTO consultas_ruc (ruc, payload, consultado_en)
VALUES (?, ?, ?)
ON CONFLICT (ruc) DO UPDATE
SET payload = excluded.payload, consultado_en = excluded.consultado_en`,
[ruc, JSON.stringify(dato ?? {}), new Date().toISOString()],
);
return dato;
}
Si quieres historial, una tabla aparte con ruc, estado, condicion y fecha registra los cambios de situación sin duplicar todo el JSON.
Si guardas cuándo consultaste, puedes cambiar el TTL mañana sin tocar los datos. Si guardas cuándo vence, cada cambio de política te obliga a recalcular toda la tabla.
Invalidación: refrescar antes de tiempo
El TTL es la regla general; la invalidación son las excepciones. Hay cuatro que vale la pena implementar.
Antes de un evento importante. Al emitir una factura, si el dato en caché tiene más de un día, consulta en vivo aunque el TTL de 30 días de la razón social no haya vencido. Es el parámetro forzar del ejemplo. Lo mismo antes de aprobar un pago grande a un proveedor o de firmar un contrato.
A mano. Un botón "actualizar datos de SUNAT" al lado de la ficha del cliente resuelve el 100 % de los "pero si ya cambió de nombre". Registra quién lo pulsó y cuándo.
Programada. Una tarea nocturna que revalida los clientes y proveedores con actividad reciente (los que tuvieron comprobantes en los últimos 30 días, por ejemplo) reparte el consumo de créditos de forma predecible y te permite generar alertas cuando un estado cambia.
Cuando la API falla. Si la consulta en vivo no responde después de los reintentos, sirve el dato en caché aunque esté vencido y márcalo en la interfaz: "validado hace 3 días". Es mucho mejor que un error en blanco.
Si cambias la estructura de lo que guardas, añade una versión a la clave de caché (ruc:v2:20131312955) para no mezclar formatos viejos y nuevos.
Cuánto ahorras en créditos
El ahorro depende de una sola variable: la proporción de consultas que se resuelven desde la caché (la tasa de aciertos). Mídela desde el primer día con dos contadores, aciertos y fallos, y compárala con las métricas de consumo del panel de tu cuenta.
Un escenario hipotético. Un sistema de facturación con 400 clientes recurrentes emite 2 500 comprobantes al mes y cada comprobante toca el RUC cuatro veces (abrir, guardar, emitir, imprimir): 10 000 consultas sin caché. Con una caché de un día, cada cliente se consulta como máximo una vez por día en que se le factura; si el cliente promedio recibe comprobantes en tres días distintos del mes, bajas a unas 1 200. Con la revalidación nocturna de los clientes activos sigues por debajo de 2 000: más del 80 % de ahorro en ese escenario, y en un CRM o un buscador interno la tasa de aciertos suele ser aún mayor.
Como los créditos prepago de endpoint.pe no vencen, el efecto práctico es que compras con menos frecuencia. Para un negocio pequeño, una buena caché puede ser la diferencia entre necesitar un plan de pago o mantenerse dentro de las 150 consultas gratuitas al mes.
El ahorro también depende de cómo cobra el proveedor: si una consulta sin resultado consume créditos o si el saldo vence a fin de mes. Esas preguntas están en cómo elegir una API de consulta RUC y DNI en Perú.
En resumen
- Los datos de identidad (razón social, nombres) casi no cambian; los de situación (estado, condición) cambian cualquier día. Dales TTL distintos.
- Estado y condición del RUC: un día, y revalida en vivo antes de emitir. Razón social: semanas. Nombres por DNI: mientras dure la relación, respetando la Ley 29733.
- El tipo de cambio de una fecha pasada y el catálogo de ubigeo no vencen nunca.
- Una tabla con fecha de consulta te da persistencia e historial; Redis te da velocidad y TTL automático. Combínalos si puedes.
- Invalida antes de eventos importantes, a mano, con una tarea nocturna acotada, y sirve dato vencido cuando la API no responde.
- Mide la tasa de aciertos; el ahorro de créditos es directamente proporcional.
Preguntas frecuentes
¿Puedo guardar en caché los nombres que devuelve la consulta de DNI?
Sí, siempre que tengas una finalidad legítima (por ejemplo, emitir el comprobante) y guardes solo lo necesario durante el tiempo necesario. La Ley 29733 exige informar esa finalidad y proteger el dato. No conserves nombres de personas con las que ya no tienes relación.
¿Qué TTL uso para el estado del RUC si emito facturas?
Un día para pantallas y reportes, y consulta en vivo si la caché tiene más de un día en el momento de emitir. El costo de un crédito es mucho menor que el de una factura emitida a un RUC dado de baja.
¿Vale la pena cachear las respuestas 404?
Para velocidad y para no consultar en bucle un RUC que no existe, sí, con un TTL corto, porque ese RUC puede inscribirse mañana. Para ahorrar dinero no hace falta: las consultas sin resultado no consumen créditos.
¿Base de datos o Redis?
Si facturas, base de datos, porque necesitas historial y evidencia. Si solo muestras datos o autocompletas formularios, Redis es suficiente. En sistemas grandes, los dos: Redis como capa rápida y la base de datos como registro permanente.






