API Documentación
URL base: https://yhfdghkh6544.com/v1. Todos los endpoints usan HTTP estándar. Puedes enviar los parámetros en la cadena de consulta (GET) o en el cuerpo JSON (POST).
Inicio rápido
- Regístrate gratis y crea una API Key en la página «API Key» de la consola.
- Incluye la API Key en la cabecera
X-Access-Keyy llama al endpoint de capturas:
curl "https://yhfdghkh6544.com/v1/screenshot?url=https://example.com&full_page=true" \
-H "X-Access-Key: $SNAPI_KEY" \
-o screenshot.pngAutenticación
Todas las peticiones requieren una API Key. Puedes enviarla de cualquiera de estas formas:
- Cabecera
X-Access-Key: snp_…(recomendada para llamadas desde el servidor) - Parámetro de consulta
access_key=snp_… - URL firmada (para incluir la URL en una página web sin exponer el secreto)
La API Key solo se muestra en texto plano una vez, al crearla. Guárdala en un lugar seguro. Si se filtra, puedes desactivarla en la consola.
Endpoint de capturas
/v1/screenshot/v1/screenshotParámetros exclusivos de las capturas:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| format | enum | png | png, jpeg o webp. |
| device_scale_factor | number | 1 | Factor de escala, 1–3. Con 2 se obtiene nitidez Retina y un tamaño de archivo aproximadamente 4 veces mayor. |
| quality | integer | 80 | Calidad JPEG / WebP, 1–100. |
| full_page | boolean | false | Captura la página completa. Se desplaza por ella para activar la carga diferida, con un límite de altura de 20,000 píxeles. |
| selector | string | — | Captura solo el primer elemento que coincida con este selector CSS. No se puede combinar con full_page. |
Parámetros comunes a capturas y PDF:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| url | string | — | URL de la página que quieres capturar, con http o https. Debes indicar este parámetro o html, pero no ambos. Se conserva el fragmento # de la URL, por lo que puedes capturar directamente páginas de aplicaciones de página única con rutas hash, como https://app.com/#/report/1. |
| html | string | — | HTML enviado directamente (máximo 2 MB). Solo admite POST. |
| viewport_width | integer | 1280 | Ancho del área de visualización, 320–3840. Con valores inferiores a 768, se renderiza como en un dispositivo móvil. |
| viewport_height | integer | 800 | Alto del área de visualización, 200–3840. |
| wait_until | enum | networkidle | Estrategia de espera: domcontentloaded (la más rápida, ideal para páginas estáticas), load o networkidle (supervisa todas las peticiones desde que se abre la página; tras la carga, espera hasta que no haya peticiones en curso durante 500 milisegundos, con un máximo de 8 segundos adicionales; ideal para aplicaciones de página única). |
| wait_for_selector | string | — | Tras cargar la página, espera hasta 10 segundos a que aparezca y sea visible un elemento que coincida con este selector CSS antes de capturar. Si no aparece, devuelve selector_not_found (sin coste). Ideal para aplicaciones de página única que renderizan contenido con temporizadores o animaciones, sin depender de peticiones de red, como .chart-ready. |
| delay | integer | 0 | Espera adicional en milisegundos una vez completada la espera inicial, 0–10000. Útil para animaciones o componentes con carga diferida. |
| block_ads | boolean | true | Bloquea las peticiones a dominios de publicidad y seguimiento. |
| block_cookie_banners | boolean | true | Oculta los avisos de consentimiento de cookies. |
| dark_mode | boolean | false | Emula prefers-color-scheme: dark. |
| hide_selectors | string | — | Lista de selectores CSS de los elementos que quieres ocultar, por ejemplo, .ad,#popup. |
| cache | boolean | true | Indica si se consulta la caché. Con false, fuerza un nuevo renderizado, pero el resultado se sigue guardando en caché. |
| cache_ttl | integer | 86400 | Tiempo de validez de la caché en segundos, 60–2592000. |
| response_type | enum | binary | binary devuelve el archivo directamente; json devuelve la URL del archivo y sus metadatos. |
Capturar aplicaciones de página única (React, Vue, etc.):La página ejecuta JavaScript en un navegador real antes de capturarse. La opción predeterminada, networkidle, espera a que termine la descarga de datos. Si el contenido se renderiza después mediante temporizadores o animaciones, añade wait_for_selector para indicar un elemento que confirme que está listo. Si no hay un elemento adecuado, usa delay para esperar un poco más.
Endpoint de PDF
/v1/pdf/v1/pdfCada PDF consume 2 créditos. Antes de imprimir, se recorre la página para activar el contenido con carga diferida. Además de los parámetros comunes, admite:
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| paper | enum | a4 | Formato de papel: a4 o letter. Si la página incluye una regla @page, se da prioridad a sus ajustes. |
| print_background | boolean | true | Imprime los colores y las imágenes de fondo. |
| pdf_media | enum | print usa los estilos de impresión; screen usa los estilos de pantalla (tal como se ve en el navegador). |
curl -X POST "https://yhfdghkh6544.com/v1/pdf" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Informe trimestral</h1><p>Contenido…</p>", "paper": "a4"}' \
-o report.pdfRespuestas
Por defecto (response_type=binary), se devuelve el archivo directamente, con Content-Type correspondiente a su formato. Cabeceras de respuesta:
X-Request-Id: ID de esta petición; inclúyelo al comunicar un problemaX-Snapi-Cache:HIToMISSX-Snapi-Truncated: true: la página completa se ha recortado por superar los 20,000 píxelesX-Snapi-Format-Changed: webp: el PNG supera los 5 MB y se ha convertido automáticamente a WebP (no se convierte si se especifica format=png de forma explícita)
Con response_type=json, se devuelven la URL del archivo y sus metadatos:
curl -X POST "https://yhfdghkh6544.com/v1/screenshot" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "response_type": "json"}'
# Devuelve
{
"url": "https://yhfdghkh6544.com/i/3f/3f9c….png",
"cache_hit": false,
"duration_ms": 1284,
"format": "png",
"width": 1280,
"height": 800,
"request_id": "req_01j…"
}URL firmadas
¿Quieres incluir la URL de la captura directamente en <img src> sin exponer tu API Key? Calcula la firma en tu servidor con el secreto asociado a la API Key (puedes consultarlo en la página API Key de la consola):
canonical = Ordena todos los parámetros, salvo signature, por nombre en orden lexicográfico.
Codifica cada par k=urlencode(v) según RFC 3986 (los espacios como %20) y únelos con &
signature = hex(HMAC-SHA256(secret, canonical))Una firma válida autentica la petición. Si se modifica cualquier parámetro (por ejemplo, url), la firma deja de ser válida. El parámetro opcional expires (segundos Unix) se incluye en la firma; una vez caducado, se devuelve signature_expired. Para actualizar la caché, cambia un parámetro sin efecto (como v=2) y vuelve a firmar. Las URL firmadas solo admiten GET.
import crypto from "node:crypto";
// Codificación RFC 3986 (espacios como %20); debe coincidir con las reglas del servidor
const enc = (v) =>
encodeURIComponent(v).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
function signedUrl(params, accessKey, secret) {
const all = { ...params, access_key: accessKey };
const canonical = Object.keys(all).sort().map((k) => `${k}=${enc(String(all[k]))}`).join("&");
const signature = crypto.createHmac("sha256", secret).update(canonical).digest("hex");
return `https://yhfdghkh6544.com/v1/screenshot?${canonical}&signature=${signature}`;
}
const src = signedUrl({ url: "https://example.com", viewport_width: 1200 }, KEY, SECRET);
// <img src={src} alt="Vista previa de la página web" />Caché
Las peticiones con los mismos parámetros usan la caché (omitir un parámetro equivale a enviar su valor predeterminado; los parámetros de autenticación y caché no se comparan). Si hay un resultado en caché, el modo binario devuelve una redirección 302 a la URL del archivo junto con Cache-Control; el navegador sigue la redirección y guarda el archivo en caché automáticamente. El modo JSON devuelve cache_hit: true.
Las respuestas desde caché no se facturan.Las peticiones simultáneas con los mismos parámetros solo generan un renderizado.
Límites y facturación
- Solo se facturan las peticiones correctas (2xx) que no usan la caché: 1 crédito por captura y 2 por PDF.
- Los tiempos de espera agotados, los fallos de renderizado, los errores del sitio de destino, los parámetros incorrectos y los fallos de autenticación no consumen créditos.
- Los créditos se renuevan cada mes natural (UTC). El plan gratuito incluye 100 créditos al mes; al agotarlos, se devuelve quota_exceeded.
- Si se supera el límite de peticiones por segundo o de concurrencia, se devuelve 429. La cabecera Retry-After indica cuántos segundos se recomienda esperar.
- Tiempo máximo de renderizado: 30 segundos; descarga máxima por página: 50 MB; tamaño máximo del archivo de salida: 50 MB.
Consulta los límites de cada plan en Precios.
Códigos de error
Todas las respuestas de error usan JSON:
{
"error": {
"code": "render_failed",
"message": "target responded with an error status",
"upstream_status": 404,
"request_id": "req_01j…"
}
}| HTTP | code | Significado | Se factura |
|---|---|---|---|
| 400 | invalid_params | Falta un parámetro o su valor está fuera de rango; message indica cuál | No |
| 400 | html_too_large | html supera los 2 MB | No |
| 401 | unauthorized | Falta la API Key, no es válida o está desactivada | No |
| 401 | signature_invalid | La firma no coincide (se han modificado los parámetros o el secreto es incorrecto) | No |
| 401 | signature_expired | La URL firmada ha caducado según expires | No |
| 403 | url_blocked | No se permite acceder a la URL de destino (por ejemplo, direcciones de red interna o localhost) | No |
| 408 | render_timeout | El renderizado ha superado los 30 segundos | No |
| 422 | render_failed | El sitio de destino devuelve 4xx/5xx, falla el DNS o hay un error de certificado; incluye upstream_status | No |
| 422 | selector_not_found | selector no coincide con ningún elemento o se ha agotado el tiempo de espera de wait_for_selector | No |
| 422 | too_many_redirects | Se han superado las 5 redirecciones | No |
| 429 | rate_limited | Se ha superado el límite de peticiones por segundo; vuelve a intentarlo según Retry-After | No |
| 429 | concurrency_exceeded | Se ha superado el límite de peticiones simultáneas | No |
| 429 | quota_exceeded | Se han agotado los créditos del mes (plan gratuito) | No |
| 429 | too_many_batches | Hay más de 5 tareas por lotes sin finalizar a la vez | No |
| 500 | internal | Error del servidor; contacta con nosotros e incluye request_id | No |
Lotes asíncronos
/v1/batch/v1/batch/{id}Envía entre 1 y 100 URL en una sola petición. El endpoint devuelve de inmediato un ID de tarea (HTTP 202) y las capturas se procesan una a una en segundo plano. Es ideal para capturar páginas por lotes sin mantener la conexión abierta. Puedes consultar el estado periódicamente o indicar webhook_url para recibir una notificación cuando todo haya terminado. La autenticación es la misma que en el endpoint síncrono (solo mediante cabecera o el parámetro access_key; no admite URL firmadas).
| Parámetro | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
| type | enum | screenshot | screenshot (captura) o pdf. |
| urls | string[] | — | URL que se van a procesar, entre 1 y 100. Si alguna no es válida, toda la petición devuelve 400 y message indica su posición. |
| options | object | {} | Parámetros comunes a todas las URL, iguales a los del endpoint síncrono (como full_page, format, viewport_width y cache_ttl). No puede incluir url, html ni response_type. |
| webhook_url | string | — | Opcional. URL a la que se enviará una notificación cuando todo haya terminado. Consulta «Notificación al finalizar». |
curl -X POST "https://yhfdghkh6544.com/v1/batch" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "screenshot",
"urls": ["https://example.com", "https://example.org"],
"options": { "full_page": true, "format": "webp" },
"webhook_url": "https://your-app.com/hooks/snapi"
}'
# Devuelve 202
{
"id": "bat_01j…",
"type": "screenshot",
"status": "queued",
"total": 2, "succeeded": 0, "failed": 0,
"created_at": "2026-10-18T09:30:00Z", "completed_at": null,
"webhook": { "url": "https://your-app.com/hooks/snapi", "status": "none", "attempts": 0 },
"items": [
{ "index": 0, "url": "https://example.com", "status": "pending", "result": null, "error": null },
{ "index": 1, "url": "https://example.org", "status": "pending", "result": null, "error": null }
]
}Consulta del progreso: el estado de la tarea, status, pasa por queued (en cola), running (en curso) y completed (todo finalizado, con éxito o con errores). El estado de cada URL es pending, running, succeeded o failed. Si se procesa correctamente, result contiene la URL del archivo; si falla, error contiene el código de error (los mismos que en el endpoint síncrono).
curl "https://yhfdghkh6544.com/v1/batch/bat_01j…" -H "X-Access-Key: $SNAPI_KEY"
{
"id": "bat_01j…",
"status": "completed",
"total": 2, "succeeded": 1, "failed": 1,
"completed_at": "2026-10-18T09:30:12Z",
"items": [
{
"index": 0, "url": "https://example.com", "status": "succeeded", "duration_ms": 1830,
"result": { "url": "https://yhfdghkh6544.com/i/3f/3f9c….webp", "mime": "image/webp", "width": 1280, "height": 2410, "cache_hit": false },
"error": null
},
{
"index": 1, "url": "https://example.org", "status": "failed", "duration_ms": 640,
"result": null,
"error": { "code": "render_failed", "message": "target responded with an error status" }
}
]
}- Se aplican las mismas reglas de facturación que en el endpoint síncrono: cada URL procesada correctamente consume 1 crédito por captura o 2 por PDF. Los resultados en caché y los fallos no consumen créditos.
- Si ya no quedan créditos al enviar la tarea, se devuelve
quota_exceededdirectamente. Si se agotan durante el procesamiento, las URL restantes fallan conquota_exceeded. - Cada cuenta puede tener como máximo 5 tareas por lotes sin finalizar a la vez. Si se supera el límite, se devuelve
too_many_batches. - La validez de los archivos resultantes depende de
options.cache_ttl(por defecto, 1 día). Descárgalos y guárdalos antes de que caduquen. - En los resultados de consulta y las notificaciones,
webhook.urlsolo se muestra hasta la ruta, sin la cadena de consulta.
Notificación al finalizar
Si indicas webhook_url, enviaremos una petición POST a esa URL cuando finalice toda la tarea. El cuerpo es JSON: { "event": "batch.completed", "batch": { … } }, donde batch es idéntico a la respuesta del endpoint de consulta. Cabeceras:
X-Snapi-Signature: t=1760779812,v1=5d3f…:tes la hora de envío (segundos Unix) yv1es la firmaX-Snapi-Event: batch.completed,X-Snapi-Delivery-Attempt: 1(número de intento de entrega)
v1 = hex(HMAC-SHA256(secret, t + "." + Cuerpo original de la solicitud))
secret es el secreto de firma de la API Key utilizada al enviar la tarea (disponible en la página API Key de la consola).- Devuelve una respuesta 2xx en un plazo de 10 segundos; de lo contrario, se considerará un fallo. En caso de fallo, se reintentará al cabo de 10 segundos, 1 minuto y 5 minutos (hasta 4 intentos en total).
- En casos excepcionales, puedes recibir notificaciones duplicadas de una misma tarea. Usa
batch.idpara descartar los duplicados. - Para verificar la firma, calcúlala a partir de los bytes originales recibidos y comprueba que la diferencia entre
ty la hora actual no supere unos minutos para evitar ataques de repetición. - La URL de callback debe ser una dirección http(s) accesible públicamente y no puede apuntar a una red interna.
import crypto from "node:crypto";
// rawBody debe contener los bytes originales recibidos, sin aplicar JSON.parse y volver a serializar
function verifySnapiWebhook(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // Protección contra ataques de repetición
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const got = Buffer.from(parts.v1 ?? "");
return got.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), got);
}
// verifySnapiWebhook(req.rawBody, req.headers["x-snapi-signature"], SNAPI_SECRET)Consulta de uso
/v1/usagecurl "https://yhfdghkh6544.com/v1/usage" -H "X-Access-Key: $SNAPI_KEY"
{ "month": "202610", "used": 37, "limit": 100, "remaining": 63, "overage": 0, "resets_at": "2026-11-01T00:00:00Z", ... }Comprobación de estado
/v1/healthNo requiere autenticación. Devuelve el estado del nodo y del pool de navegadores (total, ocupados y libres).