Démarrage rapide
Tous les endpoints utilisent https://api.ironfang.com/render comme URL de base. Le nom du produit figure dans le chemin parce que api.ironfang.com héberge toutes les API Ironfang. L'ancien chemin sans préfixe, https://api.ironfang.com/v1/, reste pris en charge pour les endpoints qui y ont été publiés auparavant. Les nouveaux endpoints utilisent l'URL de base du produit. Créez une clé API dans le portail, puis réalisez votre première capture d'écran :
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "width": 1280}' \
--output shot.pngLes requêtes de rendu réussies renvoient directement le fichier binaire en image/png, image/jpeg ou application/pdf. Les clips renvoient video/mp4. Les aperçus de site renvoient une réponse multipart contenant une affiche JPEG et une vidéo MP4. Les autres endpoints, en cas de succès, et toutes les réponses d'erreur renvoient du JSON.
Bibliothèques clientes
Des clients officiels encapsulent la même API, avec requêtes typées, vérification des webhooks et téléchargement des résultats :
npm install @ironfang/render # TypeScript, Node 20+
pip install ironfang-render # PythonIl existe aussi une CLI autonome : des binaires uniques pour Linux, macOS et Windows, avec sommes de contrôle, disponibles sur github.com/ironfang-ltd/cli.
Postman
Chaque endpoint figure dans une collection Postman publique générée à partir du contrat OpenAPI, avec un dossier "Getting started" dont la première requête ne nécessite aucune clé.
Authentification
Envoyez votre clé API comme jeton bearer avec chaque requête : Authorization: Bearer if_live_.... Créez et révoquez vos clés dans le portail. Le secret est affiché une seule fois, à la création de la clé, et il est stocké sous forme de hachage. Une clé absente ou inconnue renvoie 401 invalid_api_key.
Portées
Une clé API Ironfang peut donner accès à plusieurs produits. Choisissez ses portées lors de sa création. Les portées ne peuvent pas être étendues par la suite : créez une nouvelle clé lorsqu'un accès plus large est nécessaire. Une requête hors des portées de la clé renvoie 403 insufficient_scope et indique la portée manquante.
render:renderCaptures d'écran, PDF, images, clips et aperçus de siterender:signCréer des URL de rendu signéesrender:templates:readLire les modèles enregistrésrender:templates:writeCréer, modifier et supprimer des modèlesrender:usage:readLire l'utilisation du mois en cours
Les clés créées avant l'introduction des portées n'en ont aucune et conservent un accès complet, par souci de rétrocompatibilité. Les nouvelles clés sont toujours créées avec des portées explicites.
POST /v1/screenshot
Capture une URL ou du HTML brut avec une instance Chromium déjà démarrée. Chaque capture d'écran est décomptée une fois sur render.screenshot.
| Champ | Type | Remarques |
|---|---|---|
url | string | Page à capturer. Fournissez url ou html, pas les deux. Les cibles situées sur un réseau privé sont bloquées. |
html | string | HTML brut à capturer à la place d'une URL. |
width | int | Largeur du viewport. Par défaut : 1280. |
height | int | Hauteur du viewport. Par défaut : 800. |
device | string | desktop, tablet ou mobile. Chaque préréglage applique un viewport, une densité de pixels et un user agent. Voir Appareils. |
full_page | bool | Capture toute la hauteur de défilement au lieu du seul viewport. |
selector | string | Sélecteur CSS pour capturer un seul élément. |
dark_mode | bool | Émule prefers-color-scheme: dark. |
format | string | png (par défaut), jpeg ou webp. WebP peut produire un fichier plus léger que PNG pour la même capture. |
quality | int | Qualité JPEG et WebP de 1 à 100. Par défaut : 85. |
delay_ms | int | Temps d'attente supplémentaire après le chargement, pour les contenus affichés tardivement. |
no_cache | bool | Force une nouvelle capture en ignorant tout rendu en cache. Un nouveau rendu est décompté. Voir Cache. |
clip | object | { x, y, width, height } en pixels CSS depuis le coin supérieur gauche. Ce champ est ignoré lorsque selector est défini, car le sélecteur détermine alors la zone capturée. |
omit_background | bool | Utilise un fond transparent au lieu du fond de la page. Ce champ est ignoré pour jpeg, qui n'a pas de canal alpha. |
full_page_max_height | int | Limite une capture full_page. Sans cette limite, une page à défilement infini n'a pas de fin naturelle. |
full_page_readiness | string | scroll fait d'abord défiler une capture full_page jusqu'en bas, afin que les images loading=lazy et les contenus qui se chargent en devenant visibles figurent sur l'image. Le parcours dure au plus 10 secondes, attend au plus 0,75 s à chaque étape et s'arrête à full_page_max_height. Un budget épuisé est un avertissement sur une capture réussie. Nécessite full_page. |
success_rules | object | Règles pour les résultats qui doivent compter comme un échec, comme une page d'erreur ou un élément manquant. Voir Règles de réussite. |
Avant la capture, Ironfang Render attend les polices web, amène les animations et transitions CSS à leur état final et masque les barres de défilement. Les animations en boucle continuent de tourner.
Les sites protégés contre les robots peuvent servir une page de vérification aux navigateurs automatisés. Ironfang Render renvoie le contenu fourni par le site et ne tente pas de contourner la vérification. Lorsqu'il en reconnaît une avec certitude, la réponse porte l'avertissement bot_challenge ; toutes les pages de vérification ne sont pas reconnues.
Utilisez delay_ms lorsque le contenu continue de s'afficher après la stabilisation habituelle de la page. Exemples courants : les tableaux de bord qui chargent leurs données après le chargement de la page et les pages animées par des bibliothèques JavaScript comme GSAP.
Si des éléments manquent ou sont à moitié estompés dans votre capture, essayez delay_ms entre 500 et 1500.
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-d '{"url": "https://example.com", "full_page": true, "dark_mode": true}' \
--output page.pngAppareils
Le champ device applique ensemble un viewport, une densité de pixels, une identité mobile et un user agent. L'émulation de l'appareil est ainsi plus fidèle qu'en modifiant seulement la largeur du viewport.
| Appareil | Viewport | Densité de pixels | Taille de l'image |
|---|---|---|---|
desktop | 1280 × 800 | 1× | 1280 × 800 |
tablet | 820 × 1180 | 2× | 1640 × 2360 |
mobile | 390 × 844 | 3× | 1170 × 2532 |
Les dimensions du viewport sont en pixels CSS. Un width ou un height explicite remplace la valeur correspondante du préréglage. Un nom d'appareil inconnu renvoie une erreur de validation.
Les préréglages utilisent l'émulation d'appareils de Chromium. Ils ne contournent pas les protections contre les robots : un site peut donc toujours renvoyer une page de vérification.
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-d '{"url": "https://example.com", "device": "mobile", "format": "webp"}' \
--output phone.webpOptions communes à tous les rendus
Ces options s'appliquent aux captures d'écran, aux PDF et aux aperçus de site. Omettre une option conserve le comportement par défaut de la réponse.
Blocage
Les publicités et les traqueurs sont bloqués en tant que requêtes réseau, avant leur chargement. Les bannières de consentement sont des éléments insérés dans la page par des scripts : Ironfang Render masque donc les bannières prises en charge en CSS, après le chargement de la page.
| Champ | Type | Remarques |
|---|---|---|
block_ads | bool | Empêche les requêtes vers les réseaux publicitaires et de suivi connus. Ironfang Render utilise une liste de blocage ciblée pour limiter le risque de supprimer des ressources nécessaires à la page. |
block_cookie_banners | bool | Masque les frameworks de consentement pris en charge et lève leurs blocages du défilement. Les captures full_page peuvent ainsi dépasser un viewport. Ironfang Render ne clique sur aucun bouton d'acceptation et n'enregistre aucun consentement. |
hide_selectors | string[] | Sélecteurs CSS des éléments à masquer. Appliqués après le chargement, ils couvrent aussi les éléments injectés par script. |
CSS, JavaScript et actions de page personnalisés
Masquez un widget, ajustez les styles d'impression, sélectionnez un onglet ou dépliez un contenu avant une capture d'écran ou un PDF. Ces options fonctionnent avec une URL ou avec du HTML fourni, y compris dans les tâches en file d'attente et les lots.
Après le chargement normal de la page et les conditions d'attente, Ironfang Render applique le masquage intégré, puis votre css, attend votre script et exécute les actions dans l'ordre. La stabilisation et la capture viennent ensuite. Le wait_for_selector de premier niveau s'exécute avant ces contrôles ; utilisez une action de sélecteur pour attendre un contenu produit par une interaction.
| Champ | Type | Limites et comportement |
|---|---|---|
css | string | Une feuille de style d'au plus 65 536 octets UTF-8. Prend en charge les ajustements de mise en page, les éléments masqués, les animations désactivées et @media print. Une syntaxe incorrecte renvoie 400 bad_request avant le rendu. Chromium détermine les noms et valeurs de propriétés pris en charge. |
script | string | Du JavaScript d'au plus 16 384 octets UTF-8, exécuté dans le contexte du cadre principal de la page cible comme corps d'une fonction async. Utilisez await ou renvoyez une promesse pour un travail asynchrone. L'exécution est limitée à cinq secondes ou au délai de rendu restant, selon le plus court. Les valeurs renvoyées sont ignorées. |
actions | object[] | Jusqu'à 20 actions ordonnées, qui se partagent le budget restant de timeout_ms. Les sélecteurs ciblent la première correspondance dans la page principale et sont limités à 1 024 octets UTF-8. |
| Type d'action | Champ requis | Comportement |
|---|---|---|
click | selector | Attend un élément interactif et activé, puis clique dessus. |
hover | selector | Attend un élément interactif et place le pointeur dessus. |
wait_for_selector | selector | Attend qu'un élément existe ; il peut être masqué. |
delay | duration_ms | Attend de 0 à 10 000 ms. Au total, les délais de toutes les actions ne peuvent pas dépasser 10 000 ms. |
Cet exemple autonome masque un widget, modifie le titre et déplie le détail des tarifs avant la capture. Remplacez html par url et utilisez les sélecteurs de votre site pour capturer une page existante.
curl https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer $IRONFANG_API_KEY" \
-H 'Content-Type: application/json' \
--output expanded.png --data-binary @- <<'JSON'
{
"html": "<h1 id='title'>Plans</h1><div class='chat-widget'>Chat widget</div><details id='details'><summary id='show-more'>Show pricing</summary><p>Expanded pricing details</p></details>",
"css": ".chat-widget { display: none !important; }",
"script": "document.querySelector('#title').textContent = 'Pricing';",
"actions": [
{ "type": "click", "selector": "#show-more" },
{ "type": "wait_for_selector", "selector": "#details[open]" }
]
}
JSONUtilisez /v1/pdf et --output expanded.pdf pour obtenir le même état de page en PDF. Pour du JavaScript asynchrone, utilisez une opération attendue avec await, par exemple await new Promise(resolve => setTimeout(resolve, 250));. Pour une interface qui apparaît plus tard, faites suivre l'interaction d'une action de sélecteur.
Les entrées non valides renvoient 400 bad_request. Les erreurs de syntaxe du script, les échecs d'exécution et les dépassements de délai renvoient 422 render_failed avec un message nettoyé. Les erreurs d'action indiquent l'index (à partir de zéro) et le type, par exemple actions[0] (click), et interrompent la liste. Les rendus échoués ne sont pas décomptés ; les tâches en file d'attente ne réessaient pas ces échecs d'interaction.
Ces options et l'ordre des actions font partie de la clé de cache des captures d'écran. Une réponse servie depuis le cache renvoie l'image précédente sans exécuter à nouveau les contrôles ; définissez no_cache: true pour une nouvelle exécution. Les scripts et les clics peuvent modifier l'état de l'application cible. L'API expose des extraits de code exécutés dans le contexte de la page et ces quatre actions ; elle ne fournit ni sessions de navigateur ni API Playwright/Puppeteer.
En-têtes, cookies et identifiants
Ironfang Render applique les en-têtes, les cookies et les identifiants avant la navigation, afin qu'ils soient présents dès la première requête vers la page cible.
| Champ | Type | Remarques |
|---|---|---|
headers | object | En-têtes HTTP supplémentaires, envoyés avec chaque requête de la page. |
authorization | string | Définit l'en-tête Authorization. Une entrée Authorization explicite dans headers est prioritaire. |
cookies | object[] | { name, value, domain, path }. domain est obligatoire, car Chromium ignore un cookie sans domaine défini avant la navigation. |
user_agent | string | Remplace le user agent, y compris celui défini par device. |
Les cibles situées sur un réseau privé restent bloquées lorsque des identifiants sont fournis. La protection contre la SSRF s'exécute avant l'application des données d'authentification.
Langue et horloge
Réglez la langue et l'horloge du navigateur avant l'exécution des scripts de la page, pour que la page mette en forme dates, nombres et devises comme un visiteur sur place les verrait.
| Champ | Type | Remarques |
|---|---|---|
locale | string | Une balise BCP 47 comme en-GB ou de-DE. Définit la mise en forme par défaut d'Intl, navigator.language et navigator.languages, ainsi que l'en-tête Accept-Language avec lequel la page et ses ressources sont demandées (de-DE,de;q=0.9). |
timezone | string | Un fuseau IANA comme Europe/London ou America/New_York. Définit l'horloge de la page : Date, Intl.DateTimeFormat et tout ce qui lit l'heure locale, avec l'heure d'été propre au fuseau. Par défaut : UTC. |
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/checkout", "locale": "de-DE", "timezone": "Europe/Berlin"}' \
--output checkout-de.pngUn Accept-Language que vous placez dans headers vous appartient et est envoyé tel quel. Le navigateur ne peut alors pas annoncer une autre langue dans navigator : navigator garde sa valeur par défaut, tandis que la mise en forme Intl suit toujours locale. Chaque réponse indique ce que la page a réellement utilisé dans X-Ironfang-Locale et X-Ironfang-Timezone, et les tâches l'enregistrent dans leurs diagnostics. Les deux options s'appliquent aux captures, aux PDF, aux lots de capture, aux tâches et aux URL de capture signées.
Langue, horloge, position et adresse réseau sont quatre choses distinctes. locale et timezone changent seulement ce que le navigateur dit de sa langue et de son horloge. Elles ne donnent aucune position à l'API Geolocation et ne changent pas l'origine de la requête : chaque rendu est fait depuis le réseau d'Ironfang, quoi qu'on dise à la page. Un site qui choisit ce qu'il affiche selon l'adresse IP verra toujours le réseau d'Ironfang. Ironfang Render ne fait pas passer les requêtes par d'autres pays.
D'où viennent les rendus
Les rendus sont faits depuis le réseau d'Ironfang. Ironfang ne publie pas actuellement d'adresses sortantes fixes à autoriser : ne fondez donc pas un contrôle d'accès sur l'adresse d'où arrive un rendu. Pour laisser Render passer une connexion, un pare-feu ou une protection anti-bots sur un site que vous gérez, donnez-lui quelque chose que votre site vérifie déjà :
- Un cookie de session. Connectez un utilisateur de service, puis envoyez son cookie de session dans
cookiesavec ledomaindu cookie. Utilisez un compte qui ne voit que ce dont la capture a besoin. - Un jeton. Envoyez un jeton d'API ou un identifiant bearer dans
authorization, ou tout en-tête avec lequel votre application s'authentifie dansheaders. - Un en-tête secret partagé. Choisissez une longue valeur aléatoire, envoyez-la dans
headers(par exempleX-Render-Access) et laissez votre site ou sa périphérie faire passer la protection anti-bots aux requêtes qui la portent. Renouvelez-la comme tout identifiant.
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://app.example.com/reports/weekly",
"cookies": [{"name": "session", "value": "SERVICE_USER_SESSION", "domain": "app.example.com"}],
"headers": {"X-Render-Access": "LONG_RANDOM_SECRET"}}' \
--output weekly.pngLes identifiants ne sont envoyés qu'à la page et aux ressources qu'elle charge, ne sont jamais conservés avec l'historique des requêtes, et les cibles sur un réseau privé restent bloquées quoi que vous envoyiez. Un site que vous ne gérez pas peut bloquer volontairement les navigateurs automatisés ; Ironfang Render ne cherche pas à le contourner, et une page qui répond par une vérification est signalée comme bot_challenge.
Attente
| Champ | Type | Remarques |
|---|---|---|
wait_until | string | load (par défaut), domcontentloaded ou networkidle. networkidle attend la fin du trafic et est borné par le délai de rendu, car une page qui interroge régulièrement le serveur n'est jamais vraiment inactive. |
wait_for_selector | string | Attend cet élément avant la capture. La requête échoue si l'élément n'apparaît pas avant l'expiration du délai. |
timeout_ms | int | Délai par rendu. Les valeurs supérieures au maximum du service sont ramenées à ce maximum. |
device_scale_factor | number | Densité de pixels, de 1 à 3. 2 correspond au retina : la même taille CSS avec deux fois plus de pixels. |
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"block_ads": true,
"block_cookie_banners": true,
"wait_for_selector": "#main",
"device_scale_factor": 2
}' \
--output shot.pngRègles de réussite
Un rendu qui produit des octets est une réussite pour le navigateur, quoi que la page ait dit. Avec success_rules sur une capture ou un PDF, une page d'erreur, une page de connexion ou une page vide capturée échoue à la place. Les règles sont facultatives : sans elles, un rendu se comporte comme avant.
| Règle | Quand elle est vérifiée | Échoue lorsque |
|---|---|---|
fail_on_status | Dès que la page répond, sur son statut final après redirections, avant toute attente que la page soit prête | Le statut figure dans la liste : un code (404), une classe ("5xx") ou une plage ("400-499"). Nécessite url. |
require_selector | Une fois la page prête, avant la capture | Aucun élément ne correspond au sélecteur CSS. Il n'attend pas ; combinez-le avec wait_for_selector. |
require_text | Une fois la page prête, avant la capture | L'un des textes n'est pas affiché sur la page. Littéral, sans tenir compte de la casse ni des suites d'espaces ; le texte masqué ne compte pas. |
forbid_text | Une fois la page prête, avant la capture | L'un des textes est affiché sur la page, comparé comme pour require_text. |
fail_on_blank | Après la capture, captures uniquement | L'image est une seule couleur unie : au plus un pixel sur dix mille diffère de la couleur la plus fréquente. Une page blanche avec du texte, un dessin sur canvas ou une image n'est pas vide. |
curl -X POST https://api.ironfang.com/render/v1/screenshot \
-H "Authorization: Bearer if_live_..." \
-d '{
"url": "https://example.com/pricing",
"success_rules": {
"fail_on_status": ["4xx", "5xx"],
"require_selector": "#plans",
"forbid_text": ["Sign in to continue"]
}
}' \
--output pricing.pngUne règle non respectée donne 422 success_rule_failed ; error.rule nomme la règle, error.target_status le statut de la page, et le message nomme la valeur en cause. Une tâche échoue aussitôt et n'est pas relancée. Comme tout rendu échoué, rien n'est décompté.
Les règles font partie de la requête : une capture en cache n'est servie qu'à une requête portant les mêmes règles.
POST /v1/pdf
Imprime une URL ou du HTML brut en PDF. Chaque PDF généré avec succès est décompté une fois sur render.pdf, toutes les pages jusqu'à 100 pages comprises. Un document qui en compte davantage est refusé avec 422 pdf_too_long, et rien n'est décompté.
| Champ | Type | Remarques |
|---|---|---|
url | string | Page à imprimer. Fournissez url ou html. |
html | string | HTML brut à imprimer à la place d'une URL. |
landscape | bool | Orientation paysage. |
print_background | bool | Inclure les arrière-plans CSS. |
header_html | string | Modèle d'en-tête Chromium. Définir l'un ou l'autre modèle active les en-têtes et les pieds de page : si vous n'envoyez qu'un pied de page, envoyez donc un en-tête vide, par exemple <span></span> ; sinon, Chromium imprime son en-tête par défaut avec la date et le titre. |
footer_html | string | Modèle de pied de page Chromium. Les classes pageNumber, totalPages, date, title et url sont remplies. Les modèles n'héritent pas des styles de la page : définissez une taille de police dans chacun. |
scale | float | Échelle d'impression. Par défaut : 1,0. |
no_cache | bool | Accepté, sans effet ici : les PDF ne sont jamais mis en cache, chaque requête génère donc le document à nouveau. |
paper_format | string | a3, a4, a5, letter, legal ou tabloid. En l'absence de valeur, Chromium utilise son format par défaut, Letter. Les formats sont en portrait ; landscape les fait pivoter. |
margin | object | { top, right, bottom, left } en pouces. Les côtés omis conservent la marge par défaut de Chromium. |
paper_width / paper_height | string | Un format de page personnalisé, comme 210mm, 8.5in, 21cm, 595pt ou 794px, de 1 à 100 pouces par côté. Les deux ou aucun, et jamais avec paper_format. landscape le fait pivoter. |
prefer_css_page_size | bool | Laisser la règle @page { size: ... } de la page fixer le format. Une page qui n'en a pas garde le format ci-dessus. landscape ne fait pas pivoter un format CSS. |
page_ranges | string | Pages à conserver, numérotées à partir de 1 : 1-3, 5, 8-. Chaque page est gardée une fois, dans l'ordre du document. Les pages au-delà de la fin sont ignorées ; des plages qui n'en gardent aucune donnent 422 page_range_empty. Le document entier doit rester dans la limite de pages. |
metadata | object | Les propriétés du document PDF : title, author, subject et keywords, jusqu'à 500 caractères chacune. Sans title, le titre propre de la page est conservé. |
success_rules | object | Comme pour les captures, sauf fail_on_blank. Voir Règles de réussite. |
curl -X POST https://api.ironfang.com/render/v1/pdf \
-H "Authorization: Bearer if_live_..." \
-d '{"html": "<h1>Invoice #42</h1>", "print_background": true}' \
--output invoice.pdfPOST /v1/qr
Générez des QR codes personnalisés vérifiés avant livraison. Ironfang Render décode chaque image terminée et la compare aux données fournies. Un échec de vérification renvoie 422 unscannable, et rien n'est décompté. Chaque QR code est décompté sur render.qr, une fonction gratuite : il apparaît dans l'utilisation et n'est jamais facturé, y compris dans les modèles. Les requêtes QR sont soumises à des limites de débit.
| Champ | Type | Remarques |
|---|---|---|
data | string | Données obligatoires : une URL, une chaîne WiFi ou un texte d'au plus 1 Ko. |
size | int | Taille de sortie carrée de 64 à 2048 pixels. Par défaut : 512. PNG uniquement. |
ecc | string | Correction d'erreurs : L, M, Q ou H. Par défaut : M. L'ajout d'un logo sélectionne automatiquement H pour compenser les modules couverts par le logo. |
dark / light | string | Couleurs hexadécimales. dark doit être plus foncée que light et respecter le contraste minimal requis. Les combinaisons non valides renvoient une réponse 400. light accepte aussi transparent. Placez les codes transparents sur un fond clair. |
dots | string | square ou circle. Les motifs de repérage sont toujours dessinés pleins afin de préserver leur structure obligatoire. |
eyes | string | square ou rounded. Par défaut, identique à dots. |
margin | int | Zone de silence de 0 à 8 modules. Par défaut : 4. |
invert | bool | Crée des modules clairs sur un fond sombre. Les appareils photo des téléphones récents lisent souvent les codes inversés, mais beaucoup de lecteurs embarqués ou intégrés aux applications ne les lisent pas. Avec cette option, dark doit être plus claire que light. Ironfang Render vérifie le résultat à partir de son négatif. |
logo | string | Logo central sous forme d'URI data: en base64, png ou jpeg. Incompatible avec logo_url. |
logo_url | string | Logo central fourni par URL. L'URL est soumise à la même protection des cibles et aux mêmes limites de débit qu'une requête de capture d'écran. |
logo_size | float | Taille de la zone du logo, en fraction du symbole, de 0,12 à 0,30. Par défaut : 0,22. |
logo_pad | bool | Ajoute une zone de réserve derrière le logo pour le séparer des modules du QR code. Par défaut : true. |
curl -X POST https://api.ironfang.com/render/v1/qr \
-H "Authorization: Bearer if_live_..." \
-d '{"data": "https://example.com/menu", "dots": "rounded",
"logo_url": "https://example.com/logo.png"}' \
--output qr.pngPour inclure un QR code dans un modèle enregistré, utilisez l'objet qr des rendus de modèles. Les QR codes ne portent jamais de badge, car une marque ajoutée pourrait gêner la lecture.
POST /v1/video
Un clip : un arrière-plan, des textes qui apparaissent selon un calendrier, un filigrane facultatif et une piste audio facultative. Renvoie video/mp4.
Ironfang Render génère de courts clips à partir de données structurées pour les processus de contenu automatisés. Les requêtes utilisent la même clé API, le même compte de facturation et les mêmes intégrations que les autres types de rendu.
| Champ | Type | Remarques |
|---|---|---|
size | string | vertical 1080×1920 (par défaut), square 1080×1080, landscape 1920×1080, 720p 1280×720. |
duration | number | Durée de la sortie en secondes, de 1 à 60. Par défaut : 15. |
captions | array | Jusqu'à 12 cartons de la forme {text, from, to}, en secondes. Le texte peut contenir des guillemets, des deux-points et des parenthèses. |
colour | string | Couleur de fond hexadécimale, utilisée lorsqu'aucun background n'est fourni. Par défaut : #101820. |
background | string | URL d'une image ou d'une vidéo, recadrée pour remplir le cadre. |
watermark | string | URL d'un PNG, placé en bas à droite. |
audio | string | URL d'une piste audio, coupée à la durée du clip. |
font_size | int | Taille des textes en pixels. Par défaut, un quinzième de la largeur. |
curl -X POST https://api.ironfang.com/render/v1/video \
-H "Authorization: Bearer if_live_..." \
-d '{
"size": "vertical",
"duration": 15,
"captions": [
{"text": "Ship it on Friday", "from": 0, "to": 5},
{"text": "Find out on Monday", "from": 5, "to": 10},
{"text": "Or gate the deploy", "from": 10, "to": 15}
]
}' --output clip.mp4Utilisation
Un clip est décompté en secondes produites, arrondies à la seconde supérieure pour chaque clip : les clips vertical et landscape sont en 1080p et sont décomptés sur render.video_second_fhd, tandis que les clips square et 720p sont décomptés sur render.video_second_hd. La durée est réservée avant l'encodage et enregistrée à la livraison du clip. Un clip dont le rendu échoue n'est pas décompté, pas plus qu'une réponse servie depuis le cache.
Limites de fonctionnement
Les clips sont générés pendant la requête et limités à 60 secondes. Les fichiers référencés passent par les mêmes contrôles d'URL que les cibles de capture d'écran et sont limités à 64 Mo chacun. Les fichiers d'arrière-plan doivent être accessibles depuis l'internet public.
Les clips sont limités à 60 secondes. /v1/video génère un clip dans la requête ; pour le mettre plutôt en file d'attente et être prévenu par webhook quand il est prêt, soumettez-le comme tâche, comme décrit plus bas. Les clips plus longs ne sont pas pris en charge pour le moment.
POST /render/v1/site-preview
Transformez une page web publique en aperçu du haut vers le bas. Choisissez un balayage continu ou des étapes de la taille du viewport, avec un mouvement vif qui se pose sur une courte pause de lecture. Une requête renvoie une affiche JPEG tirée de la première image et une vidéo MP4 H.264 enregistrée dans le navigateur. Les éléments fixes et collants (sticky) se comportent comme lors d'un vrai défilement.
Cet endpoint est disponible uniquement à l'adresse https://api.ironfang.com/render/v1/site-preview.
| Champ | Type | Remarques |
|---|---|---|
url | string | Page HTTP ou HTTPS publique à enregistrer. Obligatoire. |
width | int | Largeur de sortie paire, de 320 à 1280. Par défaut : 672. |
height | int | Hauteur de sortie paire, de 240 à 1200. Par défaut : 494. L'image est limitée à 1 200 000 pixels. |
motion | string | per_page pour des étapes de la taille du viewport avec pauses, ou single_sweep pour un seul passage continu. Par défaut : per_page. |
device | string | desktop, tablet ou mobile. |
dark_mode | bool | Enregistre avec le jeu de couleurs sombre de la page. Par défaut : false. |
no_cache | bool | Force un nouvel enregistrement. Par défaut : false. |
Appelez cet endpoint depuis votre serveur, jamais depuis du code exécuté dans le navigateur : la requête contient votre clé API, et tout ce qui est envoyé à un navigateur est public. Pour un aperçu déclenché par un visiteur, créez plutôt une URL signée côté serveur.
const response = await fetch(
'https://api.ironfang.com/render/v1/site-preview',
{
method: 'POST',
headers: {
Authorization: 'Bearer if_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
motion: 'per_page'
})
}
);
const output = await response.formData();
const poster = output.get('poster'); // poster.jpg, image/jpeg
const video = output.get('video'); // preview.mp4, video/mp4Sortie et utilisation
La réponse est en multipart/form-data, avec les parties nommées poster et video. La vidéo est un MP4 H.264 à 60 images par seconde, avec une affiche JPEG tirée de la première image. Ironfang Render calcule la durée à partir de la hauteur de la page et du mouvement, dans la limite de 60 secondes fixée par le serveur. Un aperçu est décompté en secondes produites, arrondies au supérieur, sur render.site_preview_second : la limite de 60 secondes est réservée avant le début de l'enregistrement, et la durée réelle est enregistrée à la livraison de l'aperçu. L'affiche est incluse. Le travail échoué n'est pas décompté, pas plus qu'une réponse servie depuis le cache.
Un aperçu est enregistré en temps réel : la requête reste donc ouverte pendant le rendu, généralement de 30 à 90 secondes, davantage pour les pages longues ou lourdes. Réglez le délai d'expiration de votre client HTTP sur au moins 120 secondes, ou envoyez la même requête sous forme de tâche et interrogez son résultat. Un aperçu qui ne se termine pas en 90 secondes renvoie 422 render_timeout, en requête comme en tâche : la page est trop lente ou trop longue à enregistrer.
POST /render/v1/bundle
Charger une page une fois et obtenir de ce seul chargement les sorties choisies : une screenshot, le rendered_html, le text de la page, du markdown et ses metadata. Toutes les options de capture s'appliquent, des appareils et de la page entière à la préparation, aux actions et aux règles de réussite.
Cet endpoint n'est disponible qu'à https://api.ironfang.com/render/v1/bundle, ainsi que comme tâche de type bundle.
| Champ | Type | Remarques |
|---|---|---|
outputs | array | Obligatoire. Au choix parmi screenshot, rendered_html, text, markdown et metadata. format, quality, selector, clip, omit_background et fail_on_blank façonnent l'image et exigent donc screenshot. |
curl -X POST https://api.ironfang.com/render/v1/bundle \
-H "Authorization: Bearer if_live_..." \
-d '{"url": "https://example.com", "full_page": true,
"outputs": ["screenshot", "markdown", "metadata"]}' \
--output bundle.multipartconst response = await fetch('https://api.ironfang.com/render/v1/bundle', {
method: 'POST',
headers: { Authorization: 'Bearer if_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://example.com', outputs: ['markdown', 'metadata'] })
});
const parts = await response.formData();
const manifest = JSON.parse(await parts.get('manifest').text());
const markdown = await parts.get('markdown')?.text();
for (const output of manifest.outputs) {
if (output.status !== 'included') console.warn(output.name, output.status, output.reason);
}Ce que contient chaque sortie
rendered_html est le document tel que le navigateur le détient après ses scripts, la préparation et les actions, sérialisé avec son doctype. Ce n'est pas la source envoyée par le serveur. text est ce que la page affiche, tel que mis en page. markdown est produit à partir du HTML rendu, sans aucun modèle : titres, paragraphes, liens rendus absolus, images par adresse, mise en valeur, code, citations, listes et tableaux. Les scripts, les styles, les champs de formulaire et le balisage marqué comme masqué sont omis. metadata regroupe le titre, la description, la langue, l'adresse canonique, les consignes robots et les propriétés Open Graph.
Un chargement, un instant
Le HTML, le texte et les métadonnées sont lus ensemble, en une étape pendant laquelle aucun script de la page ne peut s'exécuter : ils décrivent donc un même état de la page. La capture suit immédiatement. Une page qui se modifie elle-même, comme une horloge ou un flux en direct, peut changer entre les deux : un lot est la page telle que le navigateur l'avait, pas un instantané des données du site. Le manifeste donne les deux horaires.
Le HTML, le texte et le Markdown proviennent du cadre principal. Le contenu des iframes n'est pas inclus, quelle que soit leur origine ; child_frames dans le manifeste compte les cadres omis. La capture montre ce qui a été affiché, cadres compris.
Limites et lots partiels
Le HTML rendu est conservé jusqu'à 5 Mo, le texte et le Markdown jusqu'à 1 Mo chacun. Au-delà de leur limite, le texte et le Markdown sont coupés à une frontière de caractère et marqués truncated. Le HTML au-delà de sa limite est omitted, car un HTML coupé serait un autre document, tout comme le Markdown qui en est tiré. Chaque sortie demandée figure dans le manifeste avec son statut : rien n'est omis en silence. Un lot sans aucune sortie donne 422 bundle_empty et n'est pas décompté.
Réponse et utilisation
La réponse est en multipart/form-data : d'abord manifest (JSON), puis chaque sortie incluse comme partie de fichier nommée d'après la sortie. Le manifeste donne la taille et le SHA-256 de chaque sortie, les horaires de capture ainsi que l'adresse finale et le statut de la page. Un lot réussi est décompté une fois sur render.screenshot, quelles que soient ses sorties, et rien en cas d'échec. Les lots ne sont jamais mis en cache.
Le HTML et le texte capturés sont le contenu propre de la page. Traitez-les comme des données non fiables et n'insérez jamais ce HTML dans une page à vous.
Modèles
Enregistrez du HTML réutilisable et générez-en des images avec différentes variables : images Open Graph, cartes pour les réseaux sociaux et autres ressources dynamiques. Les variables utilisent des espaces réservés {{name}}. Les valeurs substituées sont échappées en HTML pour empêcher toute injection de balisage. La gestion des modèles est gratuite ; chaque image générée avec succès est décomptée une fois sur render.image. Les identifiants sont des UUIDv7 et se trient par date de création.
| Endpoint | Objet |
|---|---|
POST /v1/templates | Créer. Corps : name, html (256 Ko max.), width, height (par défaut 1200×630, au plus 4096). |
GET /v1/templates | Lister vos modèles. |
GET /v1/templates/{id} | Récupérer un modèle. |
PUT /v1/templates/{id} | Mettre à jour. Les modifications invalident automatiquement le cache de rendu. |
DELETE /v1/templates/{id} | Supprimer. |
curl -X POST https://api.ironfang.com/render/v1/templates \
-H "Authorization: Bearer if_live_..." \
-d '{
"name": "og-card",
"html": "<div class=\"card\"><h1>{{title}}</h1><p>{{author}}</p></div>",
"width": 1200,
"height": 630
}'POST /v1/image/{id}
Génère une image à partir d'un modèle enregistré et des variables fournies. Chaque image générée avec succès est décomptée une fois sur render.image, et une réponse servie depuis le cache n'est pas décomptée.
| Champ | Type | Remarques |
|---|---|---|
vars | object | Table de chaînes qui remplit les {{placeholders}} du modèle. Les variables manquantes restent vides. |
no_cache | bool | Force une nouvelle capture en ignorant tout rendu en cache. Un nouveau rendu est décompté. Voir Cache. |
format | string | png (par défaut), jpeg ou webp. WebP peut produire un fichier plus léger que PNG pour le même résultat. |
qr | object | Spécifications de QR codes nommées, jusqu'à 4, chacune de la forme du corps de /v1/qr. Chaque entrée est générée, vérifiée par lecture et injectée comme variable {{qr.<name>}} contenant une URI data à utiliser dans un élément <img>. Les QR codes intégrés n'ajoutent aucun coût à l'image. |
curl -X POST https://api.ironfang.com/render/v1/image/0198c9f1-5b7a-7c2e-9f1d-3a8b2c4d5e6f \
-H "Authorization: Bearer if_live_..." \
-d '{"vars": {"title": "Hello from Ironfang Render", "author": "Rick"}}' \
--output og.pngPour un emplacement de QR code, placez <img src="{{qr.pay}}" width="150"> dans le modèle :
curl -X POST https://api.ironfang.com/render/v1/image/0198c9f1-5b7a-7c2e-9f1d-3a8b2c4d5e6f \
-H "Authorization: Bearer if_live_..." \
-d '{"vars": {"invoice": "INV-2041"},
"qr": {"pay": {"data": "https://pay.example/INV-2041", "size": 300}}}' \
--output invoice-card.pngModèles de documents
Enregistrez un modèle PDF une fois et rendez-le avec des données JSON structurées : valeurs imbriquées, boucles et conditions. Un modèle a un brouillon modifiable et des révisions numérotées immuables. Les rendus et tâches sans révision utilisent la révision publiée, fixée à leur acceptation : une tâche rend la révision avec laquelle elle a été acceptée, même si le modèle change pendant qu'elle attend. Chaque document compte une fois sur render.pdf, exactement comme un PDF ; la validation et la modification sont gratuites.
| Endpoint | Rôle |
|---|---|
POST /render/v1/document-templates | Créer un modèle : name, source, schema, options et sample_data. Une source qui ne se compile pas est refusée. Au plus 500 modèles par compte. |
GET /render/v1/document-templates | Lister vos modèles, sans leurs sources. ?archived=true inclut les modèles archivés. |
GET /render/v1/document-templates/{id} | Récupérer le modèle et son brouillon. |
PUT /render/v1/document-templates/{id} | Remplacer le brouillon. Ce qui est publié ne change qu'à la publication. |
DELETE /render/v1/document-templates/{id} | Archiver le modèle. Il ne peut plus être modifié, publié ni rendu sans numéro de révision ; les tâches déjà acceptées sont toujours rendues. |
POST /render/v1/document-templates/{id}/validate | Vérifier le brouillon avec des données, ou ses données d'exemple, sans imprimer ni rien décompter. La réponse indique valid et, sinon, quels champs ou quelle ligne posent problème. |
POST /render/v1/document-templates/{id}/preview | Imprimer le brouillon avec des données, ou ses données d'exemple. Un rendu PDF comme un autre ; la réponse n'est un PDF que si le rendu a réussi. |
POST /render/v1/document-templates/{id}/publish | Publier le brouillon comme révision suivante. Un brouillon inchangé republie la dernière révision. |
GET /render/v1/document-templates/{id}/revisions | Lister les révisions, la plus récente en premier. |
GET /render/v1/document-templates/{id}/revisions/{n} | Récupérer une révision avec sa source. |
POST /render/v1/document-templates/{id}/revisions/{n}/publish | Republier une révision existante : un retour en arrière, ou de nouveau en avant. |
POST /render/v1/document-templates/{id}/render | Imprimer une révision avec data, la révision publiée sauf si revision en nomme une autre. |
curl -X POST https://api.ironfang.com/render/v1/document-templates \
-H "Authorization: Bearer if_live_..." \
-d '{
"name": "invoice",
"source": "<h1>Invoice {{.number}}</h1><p>{{.customer.name}}</p><table>{{range .lines}}<tr><td>{{.description}}</td><td>{{fixed 2 .amount}}</td></tr>{{end}}</table>{{if .notes}}<p>{{.notes}}</p>{{end}}",
"schema": {
"type": "object",
"required": ["number", "customer", "lines"],
"properties": {
"number": {"type": "string"},
"customer": {"type": "object", "required": ["name"], "properties": {"name": {"type": "string"}}},
"lines": {"type": "array", "items": {"type": "object", "required": ["description", "amount"],
"properties": {"description": {"type": "string"}, "amount": {"type": "number"}}}},
"notes": {"type": "string"}
}
},
"options": {"paper_format": "a4", "print_background": true}
}'
curl -X POST https://api.ironfang.com/render/v1/document-templates/{id}/publish \
-H "Authorization: Bearer if_live_..."
curl -X POST https://api.ironfang.com/render/v1/document-templates/{id}/render \
-H "Authorization: Bearer if_live_..." \
-d '{"data": {"number": "INV-0042", "customer": {"name": "Example Trading Ltd"},
"lines": [{"description": "Widgets", "amount": 12.5}]}}' \
--output invoice.pdfLe langage des modèles
Les sources utilisent la syntaxe de html/template de Go : {{.customer.name}}, {{range .lines}}...{{end}}, {{if .notes}}...{{end}}, avec {{else}} pour une liste vide. Chaque valeur est échappée pour l'endroit où elle arrive : texte, attribut, URL (une URL de script devient #ZgotmplZ), CSS ou script. Outre les comparaisons et len, index et slice, un modèle dispose de fixed pour les décimales, mul, add, upper, lower et printf. Un modèle n'accède ni au réseau, ni aux fichiers, ni à rien d'autre que ses données, et ne peut pas s'appeler lui-même. Un rendu s'arrête à 100 000 itérations de boucle, 8 Mo de HTML ou 2 secondes.
Déclarer les données
Un modèle déclare les données dont il a besoin dans schema, un sous-ensemble strict de JSON Schema : type, properties, required, items, maxItems, maxLength, enum, nullable, default et description. Les données sont vérifiées avant toute impression, et chaque problème revient sans frais en 422 data_invalid, avec fields qui nomme chaque chemin, comme lines[2].quantity. Un champ obligatoire ne reçoit jamais de valeur par défaut. Un champ facultatif absent des données reçoit son default, ou null, de sorte que {{if .notes}} est un test. Un champ que le modèle lit et que les données ne contiennent pas est une erreur, jamais un champ de facture vide.
Imprimer des documents longs
Un modèle conserve ses options PDF avec chaque révision : format de papier, orientation, marges, arrière-plans, ainsi que header_html et footer_html avec les numéros de page. Gardez thead { display: table-header-group } pour qu'un long tableau répète sa ligne d'en-tête sur chaque page, et tr { break-inside: avoid } pour qu'aucune ligne ne soit coupée. break-before: page commence une section sur une nouvelle page. Une police système s'imprime aussitôt ; une police web depuis une URL https:// fait attendre le rendu. Utilisez des données d'exemple fictives : elles sont enregistrées avec le modèle.
URL signées
Créez une URL GET stable à utiliser dans un élément <img> ou une balise meta og:image. L'URL n'expose pas la clé API et ne nécessite pas de proxy applicatif. Sa signature couvre chaque paramètre et le compte utilisé pour la facturation, ce qui empêche toute modification après la signature.
POST /v1/sign avec :
| Champ | Type | Remarques |
|---|---|---|
kind | string | screenshot ou image. |
url | string | Page cible (kind: screenshot). |
template | string | Identifiant du modèle (kind: image). |
vars | object | Variables du modèle (kind: image). |
width / height | int | Dimensions facultatives. |
full_page | bool | Captures d'écran uniquement. |
full_page_readiness | string | Captures d'écran uniquement, avec full_page. |
success_rules | object | Captures d'écran uniquement. Signé dans l'URL : un lien qui capturerait une page d'erreur répond 422 à la place. |
ttl_hours | int | Expiration en heures. Sans valeur : 30 jours. 0 = n'expire jamais. |
La réponse contient l'url complète (et son path). L'appeler déclenche le rendu à la demande, décompté sur votre compte comme par l'endpoint correspondant : une capture signée sur render.screenshot, une image signée sur render.image. Un appel servi depuis le cache n'est pas décompté.
curl -X POST https://api.ironfang.com/render/v1/sign \
-H "Authorization: Bearer if_live_..." \
-d '{"kind": "image", "template": "0198c9f1-5b7a-7c2e-9f1d-3a8b2c4d5e6f", "vars": {"title": "My post"}, "ttl_hours": 0}'
{"url": "https://api.ironfang.com/v1/r/0/a1b2c3...?kind=image&template=0198c9f1-5b7a-7c2e-9f1d-3a8b2c4d5e6f&v.title=My+post"}Tâches
Chaque rendu ci-dessus peut aussi s'exécuter sous forme de tâche durable : vous la soumettez, recevez aussitôt un 202, interrogez son état jusqu'à ce qu'elle se termine, puis récupérez le résultat. Utilisez les tâches pour les clips, les pages lentes et partout où vous préférez ne pas garder une connexion ouverte. Les endpoints synchrones restent inchangés.
POST /render/v1/jobs
Idempotency-Key: catalogue-42-v1
{
"kind": "screenshot",
"request": { "url": "https://example.com", "full_page": true },
"external_id": "catalogue-42"
}kind vaut screenshot, pdf, qr, image, clip, site_preview, document ou bundle, et request est exactement le corps de l'endpoint correspondant (une tâche image nomme son template dans request ; la requête d'une tâche document est template, une revision facultative et data). La soumission est validée comme l'endpoint synchrone la validerait, avant toute réservation.
Suivi et résultats
GET /render/v1/jobs/{id} renvoie la tâche avec un status parmi queued, running, cancellation_requested, succeeded, failed ou cancelled. Une tâche réussie contient result (type de contenu, taille, SHA-256, expiration) et une url signée qui ne nécessite pas de clé API et reste valable 15 minutes ; GET .../result redirige vers une nouvelle URL. Le résultat hébergé est conservé en privé pendant 24 heures après le succès, puis supprimé : il s'agit d'une fenêtre de récupération, pas d'un hébergement de ressources. Conservez de votre côté ce dont vous avez besoin.
Idempotence, annulation et utilisation
Envoyez Idempotency-Key à chaque soumission. La même clé avec la même requête renvoie la tâche existante ; la même clé avec une requête différente produit 409 idempotency_conflict. DELETE .../jobs/{id} annule : une tâche en attente s'arrête aussitôt, une tâche en cours à son prochain point sûr.
Le maximum qu'une tâche peut décompter est réservé sur votre compte de facturation lorsqu'elle est acceptée, dans la même étape : une tâche qui vous a été confirmée détient donc toujours sa réservation, et un refus ne laisse aucune tâche. Cette réservation unique est conservée d'une tentative à l'autre et enregistrée, avec ce que la tâche a produit, en cas de succès ; un aperçu de site réserve la limite de 60 secondes et enregistre sa durée réelle. Une tâche qui échoue, qui est annulée en attente, ou annulée en cours sans résultat utilisable n'est pas décomptée. Le champ usage de la tâche indique son compteur et les quantités réservée et enregistrée. Les échecs temporaires sont réessayés jusqu'à trois fois avec un délai croissant ; une page dont le rendu est impossible échoue aussitôt, avec la raison.
Lots
Jusqu'à 100 tâches en une seule soumission : une requête default commune et des items qui en remplacent certaines parties. Pratique lorsque vous disposez en fait d'une liste d'URL et d'un seul jeu d'options.
POST /render/v1/batches
Idempotency-Key: nightly-2026-08-28
{
"kind": "screenshot",
"default": { "full_page": true, "block_ads": true },
"external_id": "nightly",
"items": [
{ "request": { "url": "https://example.com/a" }, "external_id": "a" },
{ "request": { "url": "https://example.com/b" }, "external_id": "b" },
{ "kind": "pdf", "request": { "url": "https://example.com/terms" } }
]
}La fusion se fait sur un seul niveau : le champ d'un élément l'emporte, tout le reste provient de la valeur par défaut. Un élément peut aussi remplacer kind et porter sa propre delivery.
Un lot est accepté ou refusé en entier. Chaque élément est validé avant qu'aucun ne soit enregistré, et tous les éléments sont admis sur votre compte de facturation en une seule étape. Un lot dont un seul élément ne peut pas être admis est donc refusé avec le code de facturation, ne réserve rien et ne laisse aucune tâche derrière lui. Chaque élément est ensuite enregistré ou libéré séparément à la fin de sa tâche. Une erreur de validation nomme l'élément dont elle provient.
Les éléments sont des tâches ordinaires : interrogez-les une par une, ou interrogez GET /render/v1/batches/{id} pour obtenir les counts par état, done et la ressource complète de chaque tâche. Il n'existe pas d'archive ZIP des résultats : configurez une destination de stockage si vous voulez réunir les sorties au même endroit, ce qui est aussi la seule solution qui fonctionne lorsque le lot compte 100 clips.
Livraison
Une tâche peut faire plus qu'attendre d'être récupérée. Enregistrez une destination, c'est-à-dire un endpoint de webhook ou votre propre bucket compatible S3, et désignez-la par son identifiant depuis n'importe quelle tâche. Les identifiants d'accès nous sont envoyés une seule fois, à la création de la destination, et ne transitent jamais dans le corps d'une tâche.
POST /render/v1/destinations
{ "type": "webhook", "name": "Production", "url": "https://hooks.example.com/render" }
→ 201 { "id": "0198f0a1...", "signing_secret": "...", "signing_secret_note": "store this now; it is not shown again" }Le secret de signature n'est affiché qu'une seule fois. Nous n'en conservons qu'une copie chiffrée : aucun endpoint ne peut donc vous le renvoyer plus tard ; si vous le perdez, créez une nouvelle destination. La gestion des destinations nécessite la portée render:destinations.
POST /render/v1/jobs
{
"kind": "screenshot",
"request": { "url": "https://example.com" },
"external_id": "catalogue-42",
"delivery": {
"webhook_destination": "0198f0a1...",
"storage_destination": "0198f0b2...",
"storage_key": "captures/{date}/{external_id}.png"
}
}Webhooks signés
Une destination de webhook est appelée lors de render.job.succeeded, render.job.failed et render.job.cancelled. Le corps contient la tâche, son usage et, en cas de succès, le type de contenu, la taille et le SHA-256 du résultat ainsi qu'une url signée, valable 15 minutes à compter de l'envoi, et non de la fin de la tâche.
Vérifiez la signature sur les octets bruts reçus, et non sur ce que vous avez analysé puis sérialisé à nouveau. La clé est le secret de signature décodé depuis l'hexadécimal : ses 32 octets, et non ses 64 caractères. verifyWebhook dans les SDK prend le secret tel qu'il a été affiché et s'en charge pour vous, à partir de la version 3.0.1 :
key = hex_decode(signing_secret) # 64 hex characters -> 32 bytes
expected = "v1=" + hmac_sha256(key, timestamp + "." + raw_body).hexdigest()
compare(expected, headers["Ironfang-Signature"]) # constant timeIronfang-Timestamp est exprimé en secondes Unix ; rejetez tout ce qui date de plus de quelques minutes pour empêcher un rejeu. Ironfang-Event-Id reste identique d'une tentative à l'autre pour une même livraison : utilisez-le pour rendre votre gestionnaire idempotent.
Les nouvelles tentatives suivent une progression d'une minute jusqu'à un jour, avec une variation aléatoire, et respectent un Retry-After borné. Nous réessayons en cas de 408, 429 et 5xx ; les autres 4xx arrêtent immédiatement les tentatives, car votre endpoint indique ainsi qu'une nouvelle tentative ne servirait à rien. Après 10 échecs consécutifs, la destination est désactivée jusqu'à ce que vous la réactiviez dans le portail.
Livraison dans votre propre bucket
Une destination s3 prend un bucket, une région, des identifiants d'accès et, en option, un endpoint et un prefix. Tout service compatible S3 fonctionne : AWS, Cloudflare R2, MinIO, Ceph. Limitez les identifiants d'accès au préfixe que vous nous indiquez : ils n'ont besoin d'écrire que là.
storage_key est la clé d'objet relative à ce préfixe. Elle accepte du texte fixe ainsi que {job_id}, {external_id} et {date} (YYYY/MM/DD), aucun autre champ, et rien n'est évalué. Par défaut, elle vaut render/{date}/{job_id}. Une clé qui sortirait du préfixe est refusée dès la soumission de la tâche, plutôt que d'être discrètement réécrite en une autre clé.
Chaque envoi reçoit une somme de contrôle et est vérifié après l'écriture ; un objet déjà présent avec la même somme de contrôle est laissé tel quel. Une livraison réessayée ne change donc rien, au lieu d'écrire une seconde fois.
La livraison ne modifie jamais un rendu
C'est sur ce point que vous pouvez compter. Une tâche dont le rendu a abouti est succeeded, quoi que votre endpoint ait fait ensuite : un webhook injoignable ne consomme pas de tentative de rendu, n'occupe pas d'emplacement de rendu et ne transforme pas une tâche réussie en échec. Les livraisons sont réessayées selon leur propre progression, et GET /render/v1/deliveries montre où en est chacune.
Si une livraison vers le stockage abandonne, la destination de webhook en est informée par un événement render.delivery.failed qui nomme la destination et l'erreur. C'est ainsi que vous apprenez qu'un bucket n'accepte plus les envois, sans devoir guetter des fichiers manquants.
Guides pratiques
Ces guides de bout en bout couvrent les processus courants avec Ironfang Render.
- Générer des images Open Graph à partir de modèles réutilisables : enregistrez un modèle, créez une URL signée pour chaque page et modifiez le design sans remplacer les URL.
- Générer des PDF de factures à partir de HTML existant : utilisez le HTML et le CSS de vos factures avec arrière-plans d'impression, numéros de page, en-têtes et pieds de page.
- Capturer une page protégée par une connexion : fournissez la session avec la requête de rendu pour capturer la page authentifiée.
- Capturer des pages sans publicités ni bannières de cookies : bloquez les requêtes réseau et masquez les fenêtres de consentement sans enregistrer de consentement.
- Captures d'écran dans GitHub Actions : capturez les aperçus de déploiement pendant les workflows de pull request, pour la relecture.
Choisissez un démarrage rapide pour Python, Node.js, PHP ou Go.
Utilisation et facturation
Ironfang Render n'a ni offres ni crédits. L'utilisation est facturée sur le compte de facturation Ironfang de votre organisation, commun à tous les produits Ironfang et que vous gérez dans Billing, dans le portail. Chaque type de travail est décompté sur un compteur :
| Travail | Compteur | Décompte |
|---|---|---|
| Capture d'écran, capture signée | render.screenshot | Un par capture d'écran ou image |
render.pdf | Un par PDF d'au plus 100 pages | |
| Image de modèle, image signée | render.image | Un par capture d'écran ou image |
| QR code | render.qr | Un par code ; une fonction gratuite, jamais facturée |
Clip, 1080p (vertical, landscape) | render.video_second_fhd | Secondes produites, arrondies au supérieur pour chaque clip |
Clip, 720p ou square | render.video_second_hd | Secondes produites, arrondies au supérieur pour chaque clip |
| Aperçu de site | render.site_preview_second | Secondes produites, arrondies au supérieur pour chaque aperçu |
| Lot de capture | render.screenshot | Un par lot, quelles que soient ses sorties |
Chaque compteur dispose d'un quota gratuit, sur chaque compte et sans carte, renouvelé le premier jour de chaque mois civil (UTC). Au-delà, l'utilisation est facturée à des tarifs par tranches une fois Pay as you go activé pour le compte de facturation, dans la limite mensuelle d'utilisation fixée pour le compte et de toute limite fixée pour Ironfang Render. Prix hors TVA. Les quotas et les tarifs de chaque compteur figurent sur la page des tarifs.
Chaque requête facturable est admise avant le début du travail : le maximum qu'elle peut décompter est réservé, et une requête qui ne peut pas être admise est refusée sans que rien ne soit fait. Ce que le travail a produit est enregistré en cas de succès, jamais plus que la réservation ; un échec, une entrée refusée ou une annulation n'enregistre rien. Les réponses facturables indiquent ce qu'elles ont décompté dans X-Ironfang-Meter et X-Ironfang-Quantity.
Quand l'utilisation est refusée
Un refus de facturation revient dans le corps d'erreur habituel avec un code stable, et rien n'est réservé ni décompté :
429 free_allowance_exhausted: le quota gratuit du mois pour ce compteur est épuisé et Pay as you go n'est pas activé. Le travail sur ce compteur s'arrête jusqu'au renouvellement du quota, et rien n'est facturé.429 account_budget_exhaustedou429 product_budget_exhausted: la limite mensuelle d'utilisation du compte, ou celle d'Ironfang Render, est atteinte. Relevez-la dans Billing ou attendez le mois suivant.402 paid_usage_paused,payment_required,payment_action_requiredouaccount_restricted: l'utilisation payante ne peut pas être facturée. Réglez le problème dans Billing.403 account_not_linked: le compte de la clé n'appartient à aucune organisation Ironfang, son utilisation ne peut donc pas être facturée.403 product_not_eligible: l'utilisation payante d'Ironfang Render exige un compte de facturation éligible.503 billing_temporarily_unavailable: la facturation n'a pas pu admettre la requête pour le moment. Réessayez après le nombre de secondes indiqué parRetry-After.
Aucun badge sur vos rendus
Rien de ce que vous générez via l'API ne porte de badge ni de filigrane Ironfang, quel que soit l'état de votre facturation. Seuls les outils gratuits anonymes d'ironfang.com marquent leurs résultats.
GET /v1/usage
L'utilisation d'Ironfang Render pour le mois civil en cours (UTC), tirée du compte de facturation de votre organisation : pour chaque compteur Render, ce qui a été utilisé, la part couverte par le quota gratuit, ce que le travail en cours réserve et ce que coûte l'utilisation enregistrée, hors taxes.
{
"product": "render",
"period_start": "2026-11-01",
"period_end": "2026-12-01",
"catalogue_version": "2026-11-1",
"mode": "free",
"currency": "GBP",
"settled": "0.00",
"reserved": "0.00",
"meters": [
{
"id": "render.screenshot",
"unit": "screenshot",
"unit_plural": "screenshots",
"free_allowance": 500,
"used": 250,
"free_used": 250,
"billable": 0,
"reserved": 1,
"remaining_free": 249,
"charge": "0.00",
"free_utility": false,
"exempt": false
},
{
"id": "render.qr",
"unit": "QR code",
"unit_plural": "QR codes",
"free_allowance": 0,
"used": 12,
"free_used": 0,
"billable": 12,
"reserved": 0,
"remaining_free": 0,
"charge": "0.00",
"free_utility": true,
"exempt": false
}
]
}used est ce qui a été enregistré ce mois-ci, free_used la part couverte par le quota gratuit et billable le reste. reserved est réservé par le travail en cours et ne s'ajoute pas à settled. charge et settled sont des montants en livres hors taxes, sous forme de chaînes décimales exactes. mode est celui du compte de facturation : enabled signifie que l'utilisation payante au-delà des quotas gratuits est activée. L'exemple montre deux des compteurs. L'ensemble du compte, c'est-à-dire chaque produit, les limites et les relevés, se trouve dans /billing/v1.
Limites de débit
Deux limites de débit s'appliquent en plus de la facturation. Chaque rendu peut générer plusieurs requêtes vers la page cible : ces limites protègent donc à la fois le site cible et le service Ironfang Render.
- 60 rendus par minute et par hôte cible, tous clients confondus. Au-delà, la réponse est
429avectarget_rate_limited. - 120 rendus par minute et par compte. Au-delà, la réponse est
429avecrate_limited.
Les réponses servies depuis le cache ne comptent pour aucune des deux limites, car elles n'envoient aucun trafic vers la cible. Les deux limites sont vérifiées après le cache et avant l'admission : une requête bloquée par une limite de débit ne réserve donc rien et ne coûte rien. Contactez Ironfang si vous avez besoin d'une limite plus élevée pour un site qui vous appartient.
En-têtes de réponse
Chaque ressource rendue indique les temps de la requête. X-Ironfang-Render-Ms contient le temps de rendu côté serveur, et X-Ironfang-Delay-Ms la part demandée via delay_ms. Les réponses servies depuis le cache portent X-Ironfang-Cache: hit, et les nouvelles captures X-Ironfang-Captured-At.
X-Ironfang-Meter nomme le compteur sur lequel une réponse facturable a été décomptée, par exemple render.screenshot, et X-Ironfang-Quantity la quantité enregistrée : un pour une capture d'écran, un PDF ou une image, les secondes produites pour une vidéo et 0 pour une réponse servie depuis le cache. Journalisez-les pour suivre l'utilisation par requête sans interroger /v1/usage.
Cache
Une requête identique renvoyée dans les 10 minutes qui suivent le rendu qui l'a produite peut être servie depuis le cache : elle porte X-Ironfang-Cache: hit et X-Ironfang-Quantity: 0, et rien n'est réservé ni décompté. Le cache est propre à chaque instance et de taille limitée : une entrée peut donc être évincée plus tôt, et une réponse depuis le cache n'est jamais garantie. Après 10 minutes, la même requête est un nouveau rendu, décompté. Les PDF ne sont jamais mis en cache. Les ressources sont renvoyées avec Cache-Control: public, max-age=3600, afin que les navigateurs et les CDN puissent les conserver une heure. Modifier un modèle invalide immédiatement son cache.
Définissez "no_cache": true lorsqu'un processus exige une nouvelle capture, par exemple pour la collecte de preuves, l'archivage ou la surveillance des modifications. Le cache est alors contourné, et le nouveau rendu est décompté. La réponse contient X-Ironfang-Captured-At avec l'heure de capture en UTC et Cache-Control: no-store pour empêcher toute mise en cache en aval.
Diagnostic
Un rendu indique ce qu'il a appris de la page, afin qu'une capture réussie d'une page 404 se distingue d'une erreur de l'API. Un rendu synchrone le renvoie en en-têtes de réponse ; le corps binaire est inchangé. Une tâche, son webhook et sa ligne d'historique des requêtes portent la même chose dans diagnostics.
| En-tête | Signification |
|---|---|
X-Ironfang-Target-Status | Le statut HTTP de la page elle-même, après redirections. Absent pour du HTML brut, qui n'a pas de réponse ; un statut n'est jamais inventé. |
X-Ironfang-Target-Redirects | Le nombre de redirections suivies par la page, s'il y en a eu. |
X-Ironfang-Settle / X-Ironfang-Settle-Ms | Comment la page s'est stabilisée avant la capture (stable, ceiling, fixed ou skipped), et en combien de temps. |
X-Ironfang-Warnings | Codes pour un résultat complet en tant que rendu mais qui n'est peut-être pas toute la page : height_capped, scroll_budget_exhausted, images_incomplete, images_broken et bot_challenge. D'autres codes peuvent s'ajouter. |
Un résultat en cache porte le diagnostic de la capture d'origine, et X-Ironfang-Captured-At indique quand elle a été faite : une ancienne capture n'est jamais présentée comme nouvelle.
Erreurs
Chaque réponse porte X-Ironfang-Request-ID, et les corps d'erreur le reprennent dans request_id. Indiquez-le lorsque vous contactez le support : nous pourrons retrouver la requête exacte. Si vous envoyez votre propre X-Request-ID (ASCII imprimable sans espaces, jusqu'à 128 caractères), il est renvoyé tel quel comme valeur de corrélation distincte.
Si les erreurs semblent venir de chez nous plutôt que de votre requête, la page d'état du service indique si quelque chose ne va pas, et le support retrouve la requête à partir de son identifiant.
Chaque erreur est un JSON avec un code stable, lisible par une machine :
{
"error": {
"code": "target_rate_limited",
"message": "too many renders of that site per minute - Ironfang Render caps how much traffic it sends to any one target",
"docs": "https://ironfang.com/render/docs#errors"
},
"request_id": "01a0c375-71de-7a40-8e19-2c7b5d9f0a63"
}docs est un lien vers cette section, et request_id est le X-Ironfang-Request-ID de la réponse qui contenait l'erreur.
| Statut | Code | Signification |
|---|---|---|
| 400 | bad_request | JSON mal formé ou paramètres non valides. |
| 401 | invalid_api_key | Clé API absente ou inconnue. |
| 402 | paid_usage_paused | L'utilisation payante ne peut pas être facturée. payment_required, payment_action_required et account_restricted sont le même refus pour d'autres raisons. Réglez le problème dans Billing. |
| 403 | bad_signature | La vérification de l'URL signée a échoué, ou l'URL a expiré. |
| 403 | account_not_linked | Le compte de la clé n'appartient à aucune organisation Ironfang, son utilisation ne peut donc pas être facturée. |
| 404 | not_found | Le modèle, la tâche, le lot, la destination, la livraison ou la route signée n'existe pas dans cette organisation. |
| 422 | render_failed | Chromium n'a pas pu générer le rendu de la cible en raison d'une URL non valide, d'une adresse privée bloquée ou d'un délai dépassé pour le sélecteur. |
| 422 | pdf_too_long | Le document compte plus de pages qu'un PDF ne peut en avoir. Rien n'est décompté. |
| 422 | page_range_empty | page_ranges ne garde aucune page du document imprimé. Rien n'est décompté. |
| 422 | bundle_empty | Aucune sortie d'un lot de capture n'a pu être incluse ; le message en donne la raison pour chacune. Rien n'est décompté. |
| 422 | success_rule_failed | Une règle de réussite a fait échouer le rendu ; error.rule la nomme. Rien n'est décompté. |
| 422 | data_invalid | Les données d'un modèle de document ne correspondent pas à son schéma ; fields nomme chaque chemin. Rien n'est décompté. |
| 422 | template_render_failed | Un modèle de document a échoué à l'exécution, par exemple en lisant un champ absent des données ; le message nomme la ligne. |
| 409 | template_unpublished | Le modèle de document n'a pas de révision publiée ; publiez-le ou nommez une révision. |
| 429 | free_allowance_exhausted | Le quota gratuit du mois pour ce compteur est épuisé et Pay as you go n'est pas activé. Rien n'est facturé ; le quota est renouvelé le premier jour du mois suivant (UTC). |
| 429 | account_budget_exhausted | La limite mensuelle d'utilisation du compte est atteinte. product_budget_exhausted signifie la même chose pour une limite fixée pour Ironfang Render. Relevez-la dans Billing ou attendez le mois suivant. |
| 503 | billing_temporarily_unavailable | La facturation n'a pas pu admettre la requête pour le moment. Réessayez après le nombre de secondes indiqué par Retry-After ; rien n'a été réservé. |
Interfaces pour machines
| Interface | Détails |
|---|---|
| Page produit | https://ironfang.com/render |
| Documentation | https://ironfang.com/render/docs |
| URL de base de l'API | https://api.ironfang.com/render |
| Contrat OpenAPI | https://api.ironfang.com/render/openapi.yaml. Le même contrat est servi en JSON à https://api.ironfang.com/render/openapi.json. |
| Authentification | Clé API de la plateforme comme jeton bearer |
| Erreurs | https://ironfang.com/render/docs#errors. Un corps JSON avec un code stable, un message, ce lien et l'identifiant de la requête. |
| MCP | Disponible. Captures d'écran, PDF, QR codes, rendus de modèles, clips, lots, URL de rendu signées, destinations de livraison par webhook, tâches et utilisation. Les destinations de stockage contiennent des identifiants et restent dans le portail. Les outils sont nommés render.*. Référence du serveur MCP ; chaque outil et chaque schéma, sans jeton, à /.well-known/ironfang-mcp.json |
| Découverte | /apis.json, /.well-known/api-catalog et /llms.txt |
Lancé sous le nom Renderwolf. Les chemins d'API, scopes, noms d'outils et en-têtes portant ce nom ont été retirés le 28 septembre 2026 ; seuls les identifiants ci-dessous, enregistrés dans des preuves signées, le conservent.

