API pública de animalitos
Resultados de los sorteos de animalitos de Venezuela, scrapeados de
tuazar.com, normalizados y servidos como JSON listo para pintar en un
sitio web: cada resultado ya trae el nombre del animalito, su número normalizado y la
URL absoluta de su imagen.
URL base
…
Todos los endpoints de esta página son relativos a esa base. Son GET,
devuelven application/json y no requieren autenticación.
El CORS lo controla la variable CORS_ORIGINS (por defecto *).
Convenciones
Forma de la respuesta
Las colecciones vienen envueltas en { total, data }. Los endpoints paginados
añaden page, limit y pages. Los de un solo recurso
devuelven { data }. Los errores devuelven { error }.
Fechas y horas
fechay los parámetrosdate/from/tosonYYYY-MM-DDen hora de Venezuela (America/Caracas).hora24esHH:MMen 24h;horarioes la etiqueta tal como la publica la fuente ("1:00 PM").drawAtes el instante exacto del sorteo en ISO 8601 UTC: úsalo para ordenar o comparar entre sorteos, no la fecha suelta.diaSemanaydiasvan de 1 = lunes a 7 = domingo.
Números y animalitos
numeroes el valor crudo de la fuente ("7"o"07") ynumeroNormalizadoel mismo relleno a dos dígitos ("07"). Compara y agrupa siempre por el normalizado.animalSluges la identidad canónica (aguila) y enlaza con/animals/:slug.animales el nombre del catálogo yanimalOriginallo que dijo la fuente en ese sorteo.
Imágenes
imagen y logo llegan como URL absoluta. Para un animalito se
resuelve en este orden: la imagen mapeada en el backoffice, la del sitio origen guardada
en el animalito y, como último recurso, el arte de ese sorteo concreto. Si no hay ninguna,
el campo es null — deja un placeholder previsto en el front.
El dominio no es necesariamente el de esta API: las rutas /uploads/… salen
por ASSETS_BASE_URL (el CDN) cuando está configurado, y por
PUBLIC_BASE_URL si no. No construyas la URL a mano ni asumas el
host: usa el valor que trae el campo. Los nombres de archivo llevan versión
(aguila-1757380000000.png) y se sirven como inmutables, así que puedes
cachearlos sin límite en el front.
Caché
Los catálogos de sorteos y animalitos se cachean 60 s en memoria, así que un cambio de imagen o de nombre hecho en el backoffice puede tardar hasta un minuto en verse aquí. Los resultados no se cachean.
Errores
Siempre el mismo cuerpo, con el mensaje en español:
{ "error": "date debe ser YYYY-MM-DD" }
| Código | Cuándo |
|---|---|
| 400 | Parámetro mal formado — sobre todo fechas que no son YYYY-MM-DD. |
| 404 | El slug pedido no existe, o la ruta no existe ("No existe GET /api/…"). |
| 500 | Fallo del servidor o de MongoDB. Se registra en los logs del contenedor. |
total: 0 y data: [].
Recetas
La tabla de hoy, con los horarios que faltan
const API = '…';
const { fecha, data } = await fetch(`${API}/results/today`).then((r) => r.json());
for (const sorteo of data) {
console.log(sorteo.nombre);
for (const r of sorteo.resultados) {
console.log(
r.pendiente
? ` ${r.horario} — pendiente`
: ` ${r.horario} — ${r.numero} ${r.animal}`,
);
}
}
Cintillo con el último resultado de cada sorteo
const { data } = await fetch(`${API}/results/latest`).then((r) => r.json());
document.querySelector('#cintillo').innerHTML = data
.map((r) => `
<div class="item">
<img src="${r.resultado.imagen ?? '/placeholder.png'}" alt="${r.resultado.animal}">
<strong>${r.resultado.numero}</strong> ${r.resultado.animal}
<small>${r.sorteo.nombre} · ${r.horario}</small>
</div>`)
.join('');
Histórico de un animalito en un sorteo
const params = new URLSearchParams({
animal: 'aguila',
lottery: 'ruletaroyal',
from: '2026-08-01',
to: '2026-08-31',
limit: '500',
sort: 'asc',
});
const { total, data } = await fetch(`${API}/results?${params}`).then((r) => r.json());
Recorrer todas las páginas de un rango grande
async function todos(query) {
const out = [];
let page = 1;
for (;;) {
const res = await fetch(`${API}/results?${query}&limit=1000&page=${page}`);
const { data, pages } = await res.json();
out.push(...data);
if (page >= pages || !data.length) return out;
page++;
}
}
API del backoffice
Además de esta API pública existe /api/admin/*, que es la que usa el
backoffice para editar resultados, configurar sorteos, subir imágenes y lanzar el
scraper. Requiere la cabecera Authorization: Bearer <ADMIN_TOKEN> y
no está pensada para consumirse desde el sitio público. Sus rutas están
listadas en el README.md del repositorio.