API Documentazione
URL di base: https://yhfdghkh6544.com/v1. Tutti gli endpoint usano HTTP standard. I parametri possono essere passati nella query string (GET) o nel corpo JSON (POST).
Guida rapida
- Registrati gratis e crea un'API Key nella pagina «API Key» della console.
- Inserisci l'API Key nell'header
X-Access-Keye chiama l'endpoint screenshot:
curl "https://yhfdghkh6544.com/v1/screenshot?url=https://example.com&full_page=true" \
-H "X-Access-Key: $SNAPI_KEY" \
-o screenshot.pngAutenticazione
Ogni richiesta richiede un'API Key, che puoi passare in uno dei seguenti modi:
- Header
X-Access-Key: snp_…(consigliato per le chiamate lato server) - Parametro di query
access_key=snp_… - URL firmato (per inserire l'URL in una pagina web senza esporre il secret)
L'API Key viene mostrata in chiaro una sola volta, al momento della creazione. Conservala al sicuro. Se viene compromessa, puoi disattivarla dalla console.
Endpoint screenshot
/v1/screenshot/v1/screenshotParametri specifici per gli screenshot:
| Parametro | Tipo | Valore predefinito | Descrizione |
|---|---|---|---|
| format | enum | png | png, jpeg o webp. |
| device_scale_factor | number | 1 | Fattore di scala, 1–3. Impostando 2 si ottiene una risoluzione Retina, con dimensioni del file circa 4 volte maggiori. |
| quality | integer | 80 | Qualità JPEG / WebP, 1–100. |
| full_page | boolean | false | Acquisisce l'intera pagina. Scorre una schermata alla volta per attivare il caricamento differito, fino a un'altezza massima di 20,000 pixel. |
| selector | string | — | Acquisisce solo il primo elemento corrispondente a questo selettore CSS. Non può essere usato insieme a full_page. |
Parametri comuni a screenshot e PDF:
| Parametro | Tipo | Valore predefinito | Descrizione |
|---|---|---|---|
| url | string | — | URL della pagina da acquisire, http o https. Usa questo parametro oppure html. Il frammento # dell'URL viene mantenuto: puoi acquisire direttamente la pagina desiderata nelle applicazioni a pagina singola con routing hash, come https://app.com/#/report/1. |
| html | string | — | HTML da inviare direttamente (massimo 2 MB). Supportato solo con POST. |
| viewport_width | integer | 1280 | Larghezza del viewport, 320–3840. Con valori inferiori a 768, la pagina viene renderizzata come su un dispositivo mobile. |
| viewport_height | integer | 800 | Altezza del viewport, 200–3840. |
| wait_until | enum | networkidle | Strategia di attesa: domcontentloaded (la più rapida, ideale per pagine statiche), load, networkidle (monitora tutte le richieste dall'apertura della pagina e, dopo il caricamento, acquisisce lo screenshot quando non ci sono richieste in corso per 500 millisecondi consecutivi; attende al massimo altri 8 secondi, ideale per applicazioni a pagina singola). |
| wait_for_selector | string | — | Dopo il caricamento della pagina, attende fino a 10 secondi che un elemento corrispondente a questo selettore CSS sia presente e visibile prima di acquisire lo screenshot. Se non compare, restituisce selector_not_found (senza addebito). Ideale per applicazioni a pagina singola che renderizzano contenuti in ritardo tramite timer o animazioni, anziché richieste di rete, come .chart-ready. |
| delay | integer | 0 | Ritardo aggiuntivo in millisecondi dopo l'attesa, 0–10000. Utile per animazioni o componenti con caricamento differito. |
| block_ads | boolean | true | Blocca le richieste ai domini pubblicitari e di tracciamento. |
| block_cookie_banners | boolean | true | Nasconde i banner di consenso ai cookie. |
| dark_mode | boolean | false | Simula prefers-color-scheme: dark. |
| hide_selectors | string | — | Elenco di selettori CSS degli elementi da nascondere, ad esempio .ad,#popup. |
| cache | boolean | true | Indica se cercare nella cache. Con false forza un nuovo rendering; il risultato viene comunque salvato nella cache. |
| cache_ttl | integer | 86400 | Durata della cache in secondi, 60–2592000. |
| response_type | enum | binary | binary restituisce direttamente il file; json restituisce l'URL del file e i metadati. |
Acquisire applicazioni a pagina singola (React, Vue, ecc.):La pagina viene eseguita in un browser reale e lo screenshot viene acquisito dopo l'esecuzione di JavaScript. La strategia predefinita networkidle attende il completamento del recupero dei dati. Se i contenuti vengono renderizzati con timer o animazioni dopo la fine delle richieste, aggiungi wait_for_selector per indicare un elemento che segnali che il contenuto è pronto. Se non c'è un elemento adatto, usa delay per attendere ancora.
Endpoint PDF
/v1/pdf/v1/pdfOgni PDF consuma 2 crediti. Prima della stampa, la pagina viene scorsa per attivare i contenuti con caricamento differito. Oltre ai parametri comuni, sono supportati:
| Parametro | Tipo | Valore predefinito | Descrizione |
|---|---|---|---|
| paper | enum | a4 | Formato carta: a4 o letter. Se la pagina definisce regole @page, queste hanno la precedenza. |
| print_background | boolean | true | Stampa colori e immagini di sfondo. |
| pdf_media | enum | print usa gli stili di stampa; screen usa gli stili a schermo (come visualizzati nel browser). |
curl -X POST "https://yhfdghkh6544.com/v1/pdf" \
-H "X-Access-Key: $SNAPI_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Report trimestrale</h1><p>Contenuto…</p>", "paper": "a4"}' \
-o report.pdfRisposte
Per impostazione predefinita (response_type=binary), viene restituito direttamente il file con il Content-Type del formato corrispondente. Header della risposta:
X-Request-Id: ID della richiesta, da fornire per la risoluzione dei problemiX-Snapi-Cache:HIToMISSX-Snapi-Truncated: true: la pagina intera è stata troncata perché supera 20,000 pixelX-Snapi-Format-Changed: webp: un PNG superiore a 5 MB è stato convertito automaticamente in WebP (nessuna conversione se format=png è specificato esplicitamente)
Impostando response_type=json, vengono restituiti l'URL del file e i metadati:
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"}'
# Risposta
{
"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 firmati
Vuoi inserire l'URL dello screenshot direttamente in <img src> senza esporre l'API Key? Calcola la firma sul tuo server usando il secret associato all'API Key (disponibile nella pagina API Key della console):
canonical = Ordina tutti i parametri, tranne signature, in ordine lessicografico per nome.
Codifica ogni coppia come k=urlencode(v) (RFC 3986, con gli spazi codificati come %20) e uniscile con &
signature = hex(HMAC-SHA256(secret, canonical))Una firma valida autentica la richiesta. Qualsiasi modifica ai parametri (ad esempio a url) invalida la firma. Il parametro facoltativo expires (secondi Unix) è incluso nella firma; dopo la scadenza viene restituito signature_expired. Per aggiornare la cache, modifica un parametro privo di effetti (come v=2) e genera una nuova firma. Gli URL firmati supportano solo GET.
import crypto from "node:crypto";
// Codifica RFC 3986 (spazi come %20), conforme alle regole del server
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="Anteprima della pagina web" />Cache
Le richieste con gli stessi parametri usano la cache (omettere un parametro equivale a specificarne il valore predefinito; i parametri di autenticazione e della cache sono esclusi dal confronto). In caso di riscontro nella cache, la modalità binaria restituisce un reindirizzamento 302 all'URL del file con Cache-Control: il browser segue automaticamente il reindirizzamento e memorizza il file nella cache. La modalità JSON restituisce cache_hit: true.
Le risposte dalla cache non vengono addebitate.Le richieste simultanee con gli stessi parametri generano un solo rendering.
Limiti e addebiti
- Vengono addebitate solo le richieste riuscite (2xx) non servite dalla cache: 1 credito per screenshot, 2 crediti per PDF.
- Timeout, rendering non riusciti, errori del sito di destinazione, parametri non validi e autenticazione non riuscita non consumano crediti.
- I crediti si rinnovano ogni mese solare (UTC). Il piano gratuito include 100 crediti al mese; una volta esauriti, viene restituito quota_exceeded.
- Se superi il limite di richieste al secondo o di richieste simultanee, viene restituito 429. L'header Retry-After indica quanti secondi attendere prima di riprovare.
- Durata massima di un rendering: 30 secondi. Download massimo per pagina: 50 MB. Dimensione massima del file generato: 50 MB.
Consulta i limiti di ogni piano: Prezzi.
Codici di errore
Tutte le risposte di errore sono in JSON:
{
"error": {
"code": "render_failed",
"message": "target responded with an error status",
"upstream_status": 404,
"request_id": "req_01j…"
}
}| HTTP | code | Significato | Addebitato |
|---|---|---|---|
| 400 | invalid_params | Parametro mancante o fuori intervallo; message indica quale | No |
| 400 | html_too_large | html supera 2 MB | No |
| 401 | unauthorized | API Key mancante, non valida o disattivata | No |
| 401 | signature_invalid | Firma non corrispondente (parametri modificati o secret errato) | No |
| 401 | signature_expired | L'URL firmato ha superato la scadenza expires | No |
| 403 | url_blocked | Accesso all'indirizzo di destinazione non consentito (ad esempio indirizzi di rete interna o localhost) | No |
| 408 | render_timeout | Il rendering ha superato 30 secondi | No |
| 422 | render_failed | Il sito di destinazione ha restituito 4xx/5xx, la risoluzione DNS è fallita o si è verificato un errore di certificato; include upstream_status | No |
| 422 | selector_not_found | selector non corrisponde ad alcun elemento oppure l'attesa di wait_for_selector è scaduta | No |
| 422 | too_many_redirects | Superato il limite di 5 reindirizzamenti | No |
| 429 | rate_limited | Superato il limite di richieste al secondo; riprova seguendo Retry-After | No |
| 429 | concurrency_exceeded | Superato il limite di richieste simultanee | No |
| 429 | quota_exceeded | Crediti mensili esauriti (piano gratuito) | No |
| 429 | too_many_batches | Superato il limite di 5 batch in corso | No |
| 500 | internal | Errore del server. Contattaci fornendo request_id | No |
Batch asincroni
/v1/batch/v1/batch/{id}Invia da 1 a 100 URL in una sola richiesta: l'endpoint restituisce subito un ID attività (HTTP 202) e acquisisce gli screenshot uno alla volta in background. Ideale per acquisizioni in batch senza mantenere aperta la connessione. Puoi interrogare periodicamente l'endpoint di stato oppure specificare webhook_url per ricevere una notifica al completamento. L'autenticazione è la stessa degli endpoint sincroni (solo tramite header o parametro access_key; gli URL firmati non sono supportati).
| Parametro | Tipo | Valore predefinito | Descrizione |
|---|---|---|---|
| type | enum | screenshot | screenshot (screenshot) o pdf. |
| urls | string[] | — | URL da elaborare, da 1 a 100. Se anche uno solo non è valido, l'intera richiesta restituisce 400; message ne indica la posizione. |
| options | object | {} | Parametri comuni a tutti gli URL, gli stessi degli endpoint sincroni (ad esempio full_page, format, viewport_width, cache_ttl). Non possono includere url, html, response_type. |
| webhook_url | string | — | Facoltativo. URL a cui inviare la notifica al termine di tutte le elaborazioni. Vedi «Webhook di completamento». |
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"
}'
# Risposta 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 }
]
}Verifica l'avanzamento: lo stato status dell'attività passa da queued (in coda) a running (in elaborazione), fino a completed (tutte le elaborazioni terminate, riuscite o meno). Ogni URL ha uno stato tra pending, running, succeeded e failed. In caso di successo, result contiene l'URL del file; in caso di errore, error contiene il codice di errore (gli stessi degli endpoint sincroni).
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" }
}
]
}- Gli addebiti seguono le stesse regole degli endpoint sincroni: ogni URL elaborato con successo consuma 1 credito per screenshot o 2 per PDF. Le risposte dalla cache e le elaborazioni non riuscite non consumano crediti.
- Se i crediti sono già esauriti al momento dell'invio, viene restituito subito
quota_exceeded. Se si esauriscono durante l'elaborazione, gli URL rimanenti falliscono conquota_exceeded. - Ogni account può avere al massimo 5 batch in corso. Oltre questo limite viene restituito
too_many_batches. - La validità dei file generati è determinata da
options.cache_ttl(1 giorno per impostazione predefinita). Scaricali e salvali prima della scadenza. - Nelle risposte di stato e nei webhook,
webhook.urlviene mostrato solo fino al percorso, senza la query string.
Webhook di completamento
Se specifichi webhook_url, al completamento di tutte le elaborazioni inviamo a quell'URL una richiesta POST con corpo JSON: { "event": "batch.completed", "batch": { … } }. Il campo batch è identico alla risposta dell'endpoint di stato. Header della richiesta:
X-Snapi-Signature: t=1760779812,v1=5d3f…:tè l'ora di invio (secondi Unix),v1è la firmaX-Snapi-Event: batch.completed,X-Snapi-Delivery-Attempt: 1(numero del tentativo di invio)
v1 = hex(HMAC-SHA256(secret, t + "." + Corpo originale della richiesta))
secret è il segreto di firma associato all’API Key usata per inviare il task (disponibile nella pagina API Key della console)- Restituisci una risposta 2xx entro 10 secondi, altrimenti l’invio sarà considerato fallito. In caso di errore, verranno effettuati nuovi tentativi dopo 10 secondi, 1 minuto e 5 minuti (fino a 4 tentativi in totale).
- In casi molto rari potresti ricevere notifiche duplicate per lo stesso task. Usa
batch.idper deduplicarle. - Per verificare la firma, calcolala sui byte originali ricevuti e controlla che
tnon differisca dall’ora corrente di più di qualche minuto, per prevenire attacchi replay. - L’indirizzo di callback deve essere un indirizzo http(s) accessibile pubblicamente e non può puntare a una rete privata.
import crypto from "node:crypto";
// rawBody deve contenere i byte originali ricevuti, senza eseguire prima JSON.parse e poi serializzare di nuovo
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; // Protezione dagli attacchi replay
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)Verifica dei consumi
/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", ... }Controllo di stato
/v1/healthNon richiede autenticazione. Restituisce lo stato del nodo e del pool di browser (totali, occupati, disponibili).