Développeurs

Démarrer avec l'API

Une API HTTP en JSON, sans SDK. URL de base : https://api.pdf-realm.io

Démarrer

Créez votre compte, puis une clé dans l'application (« Documents générés » → « Clés d'API »). Passez-la dans l'en-tête Authorization de chaque requête :

Authorization: Bearer pdfr_…

La clé n'est affichée qu'à sa création. Gardez-la côté serveur : elle donne accès à tous les documents de l'espace. Une clé compromise se révoque depuis l'application, sans toucher aux autres.

Modèles

Un modèle est un composant Vue : du HTML, du CSS, et les données de la requête reçues en props. On l'écrit dans l'éditeur de l'application, avec un aperçu en direct. Son identifiant est affiché sous « Informations API ».

<template>
  <div class="page">
    <h1>Facture n° {{ numero }}</h1>
    <p>Client : {{ client }}</p>
    <table>
      <tr v-for="ligne in lignes" :key="ligne.libelle">
        <td>{{ ligne.libelle }}</td>
        <td class="montant">{{ ligne.montant }} €</td>
      </tr>
    </table>
  </div>
</template>

<script>
export default {
  props: ['numero', 'client', 'lignes']
}
</script>

Générer un document

POST /documents/sync répond une fois le PDF prêt, avec un downloadUrl utilisable sans clé pendant une heure.

curl https://api.pdf-realm.io/documents/sync \
  -H "Authorization: Bearer $PDF_REALM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "facture",
    "data": {
      "numero": 42,
      "client": "Dupont SARL",
      "lignes": [{ "libelle": "Conseil", "montant": 1200 }]
    },
    "filename": "facture-42.pdf"
  }'
templateIdentifiant du modèle (requis, sauf avec pageUrl).
pageUrlOu bien : une page web publique à imprimer telle quelle.
dataObjet JSON transmis au modèle.
filenameNom du fichier PDF ; par défaut document-<id>.pdf.
metaObjet JSON libre (4 Ko max), renvoyé tel quel avec le document.
webhookUrlWebhook propre à ce document ; sinon celui de l'espace.
pdfOptionsformat, landscape, margin, scale, printBackground, pageRanges, headerTemplate, footerTemplate…

Mode asynchrone

Pour une application, préférez POST /documents : la réponse 202 arrive immédiatement et le PDF est généré dès que vient son tour. Récupérez-le par webhook, ou en interrogeant GET /documents/<id> jusqu'au statut success.

curl https://api.pdf-realm.io/documents \
  -H "Authorization: Bearer $PDF_REALM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "facture",
    "data": { "numero": 42 },
    "webhookUrl": "https://exemple.fr/webhooks/pdf-realm"
  }'

# 202 Accepted
# { "id": "093e3ec6-…", "status": "pending", "downloadUrl": null, … }

Imprimer une page web

Sans modèle, pageUrl imprime une page publique telle quelle. Les adresses privées (localhost, réseaux internes) sont refusées.

curl https://api.pdf-realm.io/documents/sync \
  -H "Authorization: Bearer $PDF_REALM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "pageUrl": "https://exemple.fr/rapport/2026-10",
    "pdfOptions": { "format": "A4", "landscape": true }
  }'

Webhooks

À la fin de chaque document, PDF Realm envoie un POST au webhook du document, ou à défaut à celui de l'espace. event vaut document.generated ou document.failed. Répondez par un code 2xx dans les 10 secondes ; sinon l'appel est réessayé après 1, 5 puis 30 minutes.

{
  "event": "document.generated",
  "document": {
    "id": "093e3ec6-5e80-4865-bf20-54ab72e2b39d",
    "status": "success",
    "filename": "facture-42.pdf",
    "meta": { "facture": 42 },
    "downloadUrl": "https://api.pdf-realm.io/documents/093e…/pdf?…"
  }
}

Chaque appel est signé : vérifiez l'en-tête X-Pdf-Realm-Signature avec le secret de webhook de l'espace (whsec_…).

import crypto from 'node:crypto'

// En-tête X-Pdf-Realm-Signature: t=1793455563,v1=5f2b…
function signatureValide(entete, corpsBrut, secret) {
  const { t, v1 } = Object.fromEntries(entete.split(',').map(p => p.split('=')))
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const attendue = crypto.createHmac('sha256', secret).update(`${t}.${corpsBrut}`).digest('hex')
  return attendue.length === v1.length && crypto.timingSafeEqual(Buffer.from(attendue), Buffer.from(v1))
}

Quotas

Chaque offre inclut un nombre de documents par mois civil (UTC). Seuls les PDF réussis comptent. Quota atteint, la création est refusée en 402 jusqu'au 1er du mois suivant. La consommation en cours est donnée par GET /space/usage. Voir les offres.

Erreurs

Une requête refusée renvoie un code 4xx et un message en texte.

400Saisie invalide (le message indique quel champ).
401Clé d'API absente, inconnue ou révoquée.
402Quota mensuel atteint.
404Modèle ou document introuvable dans votre espace.
409Opération impossible dans l'état du document.