Aller au contenu
Se connecter

Référence de l'API

Retrouvez les endpoints, les paramètres de requête, l'authentification, l'utilisation et la facturation, les en-têtes de réponse et les codes d'erreur de l'API Ironfang Render.

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.png

Les 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     # Python

Il 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é.

Exécuter dans PostmanVoir la collection

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 site
  • render:signCréer des URL de rendu signées
  • render:templates:readLire les modèles enregistrés
  • render:templates:writeCréer, modifier et supprimer des modèles
  • render: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.

ChampTypeRemarques
urlstringPage à capturer. Fournissez url ou html, pas les deux. Les cibles situées sur un réseau privé sont bloquées.
htmlstringHTML brut à capturer à la place d'une URL.
widthintLargeur du viewport. Par défaut : 1280.
heightintHauteur du viewport. Par défaut : 800.
devicestringdesktop, tablet ou mobile. Chaque préréglage applique un viewport, une densité de pixels et un user agent. Voir Appareils.
full_pageboolCapture toute la hauteur de défilement au lieu du seul viewport.
selectorstringSélecteur CSS pour capturer un seul élément.
dark_modeboolÉmule prefers-color-scheme: dark.
formatstringpng (par défaut), jpeg ou webp. WebP peut produire un fichier plus léger que PNG pour la même capture.
qualityintQualité JPEG et WebP de 1 à 100. Par défaut : 85.
delay_msintTemps d'attente supplémentaire après le chargement, pour les contenus affichés tardivement.
no_cacheboolForce une nouvelle capture en ignorant tout rendu en cache. Un nouveau rendu est décompté. Voir Cache.
clipobject{ 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_backgroundboolUtilise 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_heightintLimite une capture full_page. Sans cette limite, une page à défilement infini n'a pas de fin naturelle.
full_page_readinessstringscroll 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_rulesobjectRè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.png

Appareils

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.

AppareilViewportDensité de pixelsTaille de l'image
desktop1280 × 8001×1280 × 800
tablet820 × 11802×1640 × 2360
mobile390 × 8443×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.webp

Options 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.

ChampTypeRemarques
block_adsboolEmpê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_bannersboolMasque 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_selectorsstring[]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.

ChampTypeLimites et comportement
cssstringUne 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.
scriptstringDu 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.
actionsobject[]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'actionChamp requisComportement
clickselectorAttend un élément interactif et activé, puis clique dessus.
hoverselectorAttend un élément interactif et place le pointeur dessus.
wait_for_selectorselectorAttend qu'un élément existe ; il peut être masqué.
delayduration_msAttend 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]" }
  ]
}
JSON

Utilisez /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.

ChampTypeRemarques
headersobjectEn-têtes HTTP supplémentaires, envoyés avec chaque requête de la page.
authorizationstringDéfinit l'en-tête Authorization. Une entrée Authorization explicite dans headers est prioritaire.
cookiesobject[]{ name, value, domain, path }. domain est obligatoire, car Chromium ignore un cookie sans domaine défini avant la navigation.
user_agentstringRemplace 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.

ChampTypeRemarques
localestringUne 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).
timezonestringUn 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.png

Un 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 cookies avec le domain du 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 dans headers.
  • Un en-tête secret partagé. Choisissez une longue valeur aléatoire, envoyez-la dans headers (par exemple X-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.png

Les 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

ChampTypeRemarques
wait_untilstringload (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_selectorstringAttend 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_msintDélai par rendu. Les valeurs supérieures au maximum du service sont ramenées à ce maximum.
device_scale_factornumberDensité 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.png

Rè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ègleQuand elle est vérifiéeÉchoue lorsque
fail_on_statusDès que la page répond, sur son statut final après redirections, avant toute attente que la page soit prêteLe statut figure dans la liste : un code (404), une classe ("5xx") ou une plage ("400-499"). Nécessite url.
require_selectorUne fois la page prête, avant la captureAucun élément ne correspond au sélecteur CSS. Il n'attend pas ; combinez-le avec wait_for_selector.
require_textUne fois la page prête, avant la captureL'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_textUne fois la page prête, avant la captureL'un des textes est affiché sur la page, comparé comme pour require_text.
fail_on_blankAprès la capture, captures uniquementL'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.png

Une 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é.

ChampTypeRemarques
urlstringPage à imprimer. Fournissez url ou html.
htmlstringHTML brut à imprimer à la place d'une URL.
landscapeboolOrientation paysage.
print_backgroundboolInclure les arrière-plans CSS.
header_htmlstringModè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_htmlstringModè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.
scalefloatÉchelle d'impression. Par défaut : 1,0.
no_cacheboolAccepté, sans effet ici : les PDF ne sont jamais mis en cache, chaque requête génère donc le document à nouveau.
paper_formatstringa3, 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.
marginobject{ top, right, bottom, left } en pouces. Les côtés omis conservent la marge par défaut de Chromium.
paper_width / paper_heightstringUn 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_sizeboolLaisser 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_rangesstringPages à 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.
metadataobjectLes 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_rulesobjectComme 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.pdf

POST /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.

ChampTypeRemarques
datastringDonnées obligatoires : une URL, une chaîne WiFi ou un texte d'au plus 1 Ko.
sizeintTaille de sortie carrée de 64 à 2048 pixels. Par défaut : 512. PNG uniquement.
eccstringCorrection 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 / lightstringCouleurs 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.
dotsstringsquare ou circle. Les motifs de repérage sont toujours dessinés pleins afin de préserver leur structure obligatoire.
eyesstringsquare ou rounded. Par défaut, identique à dots.
marginintZone de silence de 0 à 8 modules. Par défaut : 4.
invertboolCré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.
logostringLogo central sous forme d'URI data: en base64, png ou jpeg. Incompatible avec logo_url.
logo_urlstringLogo 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_sizefloatTaille de la zone du logo, en fraction du symbole, de 0,12 à 0,30. Par défaut : 0,22.
logo_padboolAjoute 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.png

Pour 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.

ChampTypeRemarques
sizestringvertical 1080×1920 (par défaut), square 1080×1080, landscape 1920×1080, 720p 1280×720.
durationnumberDurée de la sortie en secondes, de 1 à 60. Par défaut : 15.
captionsarrayJusqu'à 12 cartons de la forme {text, from, to}, en secondes. Le texte peut contenir des guillemets, des deux-points et des parenthèses.
colourstringCouleur de fond hexadécimale, utilisée lorsqu'aucun background n'est fourni. Par défaut : #101820.
backgroundstringURL d'une image ou d'une vidéo, recadrée pour remplir le cadre.
watermarkstringURL d'un PNG, placé en bas à droite.
audiostringURL d'une piste audio, coupée à la durée du clip.
font_sizeintTaille 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.mp4

Utilisation

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.

ChampTypeRemarques
urlstringPage HTTP ou HTTPS publique à enregistrer. Obligatoire.
widthintLargeur de sortie paire, de 320 à 1280. Par défaut : 672.
heightintHauteur de sortie paire, de 240 à 1200. Par défaut : 494. L'image est limitée à 1 200 000 pixels.
motionstringper_page pour des étapes de la taille du viewport avec pauses, ou single_sweep pour un seul passage continu. Par défaut : per_page.
devicestringdesktop, tablet ou mobile.
dark_modeboolEnregistre avec le jeu de couleurs sombre de la page. Par défaut : false.
no_cacheboolForce 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/mp4

Sortie 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.

ChampTypeRemarques
outputsarrayObligatoire. 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.multipart
const 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.

EndpointObjet
POST /v1/templatesCréer. Corps : name, html (256 Ko max.), width, height (par défaut 1200×630, au plus 4096).
GET /v1/templatesLister 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.

ChampTypeRemarques
varsobjectTable de chaînes qui remplit les {{placeholders}} du modèle. Les variables manquantes restent vides.
no_cacheboolForce une nouvelle capture en ignorant tout rendu en cache. Un nouveau rendu est décompté. Voir Cache.
formatstringpng (par défaut), jpeg ou webp. WebP peut produire un fichier plus léger que PNG pour le même résultat.
qrobjectSpé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.png

Pour 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.png

Modè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.

EndpointRôle
POST /render/v1/document-templatesCré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-templatesLister 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}/validateVé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}/previewImprimer 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}/publishPublier le brouillon comme révision suivante. Un brouillon inchangé republie la dernière révision.
GET /render/v1/document-templates/{id}/revisionsLister 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}/publishRepublier une révision existante : un retour en arrière, ou de nouveau en avant.
POST /render/v1/document-templates/{id}/renderImprimer 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.pdf

Le 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 :

ChampTypeRemarques
kindstringscreenshot ou image.
urlstringPage cible (kind: screenshot).
templatestringIdentifiant du modèle (kind: image).
varsobjectVariables du modèle (kind: image).
width / heightintDimensions facultatives.
full_pageboolCaptures d'écran uniquement.
full_page_readinessstringCaptures d'écran uniquement, avec full_page.
success_rulesobjectCaptures d'écran uniquement. Signé dans l'URL : un lien qui capturerait une page d'erreur répond 422 à la place.
ttl_hoursintExpiration 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 time

Ironfang-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.

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 :

TravailCompteurDécompte
Capture d'écran, capture signéerender.screenshotUn par capture d'écran ou image
PDFrender.pdfUn par PDF d'au plus 100 pages
Image de modèle, image signéerender.imageUn par capture d'écran ou image
QR coderender.qrUn par code ; une fonction gratuite, jamais facturée
Clip, 1080p (vertical, landscape)render.video_second_fhdSecondes produites, arrondies au supérieur pour chaque clip
Clip, 720p ou squarerender.video_second_hdSecondes produites, arrondies au supérieur pour chaque clip
Aperçu de siterender.site_preview_secondSecondes produites, arrondies au supérieur pour chaque aperçu
Lot de capturerender.screenshotUn 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_exhausted ou 429 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_required ou account_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é par Retry-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 429 avec target_rate_limited.
  • 120 rendus par minute et par compte. Au-delà, la réponse est 429 avec rate_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êteSignification
X-Ironfang-Target-StatusLe 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-RedirectsLe nombre de redirections suivies par la page, s'il y en a eu.
X-Ironfang-Settle / X-Ironfang-Settle-MsComment la page s'est stabilisée avant la capture (stable, ceiling, fixed ou skipped), et en combien de temps.
X-Ironfang-WarningsCodes 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.

StatutCodeSignification
400bad_requestJSON mal formé ou paramètres non valides.
401invalid_api_keyClé API absente ou inconnue.
402paid_usage_pausedL'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.
403bad_signatureLa vérification de l'URL signée a échoué, ou l'URL a expiré.
403account_not_linkedLe compte de la clé n'appartient à aucune organisation Ironfang, son utilisation ne peut donc pas être facturée.
404not_foundLe modèle, la tâche, le lot, la destination, la livraison ou la route signée n'existe pas dans cette organisation.
422render_failedChromium 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.
422pdf_too_longLe document compte plus de pages qu'un PDF ne peut en avoir. Rien n'est décompté.
422page_range_emptypage_ranges ne garde aucune page du document imprimé. Rien n'est décompté.
422bundle_emptyAucune sortie d'un lot de capture n'a pu être incluse ; le message en donne la raison pour chacune. Rien n'est décompté.
422success_rule_failedUne règle de réussite a fait échouer le rendu ; error.rule la nomme. Rien n'est décompté.
422data_invalidLes données d'un modèle de document ne correspondent pas à son schéma ; fields nomme chaque chemin. Rien n'est décompté.
422template_render_failedUn modèle de document a échoué à l'exécution, par exemple en lisant un champ absent des données ; le message nomme la ligne.
409template_unpublishedLe modèle de document n'a pas de révision publiée ; publiez-le ou nommez une révision.
429free_allowance_exhaustedLe 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).
429account_budget_exhaustedLa 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.
503billing_temporarily_unavailableLa 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

InterfaceDétails
Page produithttps://ironfang.com/render
Documentationhttps://ironfang.com/render/docs
URL de base de l'APIhttps://api.ironfang.com/render
Contrat OpenAPIhttps://api.ironfang.com/render/openapi.yaml. Le même contrat est servi en JSON à https://api.ironfang.com/render/openapi.json.
AuthentificationClé API de la plateforme comme jeton bearer
Erreurshttps://ironfang.com/render/docs#errors. Un corps JSON avec un code stable, un message, ce lien et l'identifiant de la requête.
MCPDisponible. 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.