Aller au contenu

Créer un PDF en asynchrone, avec webhooks

Mettez un PDF en file d’attente et récupérez le résultat plus tard : en interrogeant l’endpoint de la tâche, ou par une notification webhook. Adapté aux gros documents, aux lots, et à tout flux qui ne doit pas garder une connexion HTTP ouverte jusqu’à la fin du rendu.

POST https://api.templatefox.com/v1/pdf/create-async

Authentification : clé API dans l’en-tête x-api-key. Crédits : 1 crédit débité à la mise en file de la tâche (remboursé si la tâche échoue définitivement).

Pour une génération immédiate, utilisez create-pdf.

  1. Vous appelez POST /v1/pdf/create-async avec votre template_id et vos data : vous recevez aussitôt un job_id.
  2. La tâche passe par pending → processing → completed ou failed.
  3. Le résultat vous parvient de deux façons (ou des deux) :
    • Interrogation — appelez GET /v1/pdf/jobs/{job_id} jusqu’à ce que status vaille completed ou failed.
    • Webhook — passez une webhook_url dans la requête : nous y envoyons un POST quand la tâche se termine.

Les deux modes fonctionnent en même temps. Le webhook est facultatif.

ChampTypeDescription
template_idstringL’identifiant du template, 12 caractères.
dataobjectLes paires clé-valeur correspondant aux variables du template.
curl -X POST https://api.templatefox.com/v1/pdf/create-async \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "template_id": "HMQywVpZxqAM",
  "data": {
    "customer_name": "John Doe",
    "invoice_number": "INV-001"
  },
  "webhook_url": "https://example.com/webhooks/pdf"
}'

Ou passez par l’un de nos SDK officiels : TypeScript, Python, Go, PHP, Ruby, Java, C#.

ChampTypeObligatoireDéfautDescription
template_idstring✅—Identifiant du template, 12 caractères.
dataobject✅—Les données clé-valeur injectées dans le template.
export_typestring—"url"En asynchrone, seule la valeur "url" est prise en charge pour l’instant. Pour une réponse binaire, utilisez create-pdf.
expirationinteger—86400Durée de validité de l’URL signée, en secondes (60 à 604800).
filenamestring—"document"Nom de fichier personnalisé (sans extension).
store_s3boolean—falseEnvoie le fichier dans votre bucket S3 configuré plutôt que sur notre CDN.
s3_filepathstring——Préfixe de chemin dans votre bucket S3.
s3_bucketstring——Remplace le nom de bucket de votre intégration S3.
webhook_urlstring——URL publique notifiée à la fin de la tâche, en cas de succès comme d’échec. Les adresses privées ou locales sont refusées.
webhook_secretstring——Secret (16 à 256 caractères) qui sert à signer le contenu des webhooks en HMAC-SHA256.
pdf_variantstring——"pdf/a-1b", "pdf/a-2b" ou "pdf/a-3b", pour un PDF conforme aux normes d’archivage.
versionstring——Tag ou numéro de version du template.

Une requête asynchrone complète : webhook signé en HMAC, envoi vers S3, nom de fichier personnalisé, conformité PDF/A.

curl -X POST https://api.templatefox.com/v1/pdf/create-async \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "template_id": "HMQywVpZxqAM",
  "data": { "invoice_number": "INV-001" },
  "filename": "invoice-001",
  "store_s3": true,
  "s3_filepath": "invoices/2026/04/",
  "pdf_variant": "pdf/a-2b",
  "webhook_url": "https://example.com/webhooks/pdf",
  "webhook_secret": "whk_a1b2c3d4e5f6g7h8i9j0k1l2"
}'

Quand la tâche se termine, le contenu du webhook porte result.s3_bucket et result.s3_key à la place de result.url, et chaque requête porte un en-tête X-TemplateFox-Signature : voir Vérifier la signature.

{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"credits_remaining": 99
}
ChampTypeDescription
job_idstringUUID à interroger, ou à rapprocher des notifications webhook.
statusstringToujours "pending" à la création.
credits_remainingnumberCrédits restants après le débit.

Renvoie l’état actuel d’une tâche.

curl https://api.templatefox.com/v1/pdf/jobs/550e8400-e29b-41d4-a716-446655440000 \
-H "x-api-key: YOUR_API_KEY"
StatutDescription
pendingEn file d’attente, pas encore pris en charge.
processingLe PDF est en cours de rendu.
completedLe PDF est prêt : voir result_url, ou result_s3_bucket / result_s3_key.
failedLa tâche a échoué : voir error_message et error_code. Le crédit est remboursé.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"template_id": "HMQywVpZxqAM",
"export_type": "url",
"filename": "invoice-001",
"store_s3": false,
"created_at": "2026-04-24T12:00:00Z",
"updated_at": "2026-04-24T12:00:05Z",
"completed_at": "2026-04-24T12:00:05Z",
"result_url": "https://cdn.templatefox.com/generated/abc123/invoice-001.pdf",
"result_filename": "invoice-001.pdf",
"result_expires_at": "2026-04-25T12:00:05Z",
"result_s3_bucket": null,
"result_s3_key": null,
"error_message": null,
"error_code": null
}
  • Toutes les 1 à 2 secondes pour les petits documents.
  • Toutes les 5 à 10 secondes pour les gros documents ou les lots.
  • Avec des délais croissants (attente exponentielle) quand beaucoup de tâches tournent en même temps.
  • Un webhook évite ces appels répétés.

Si vous fournissez une webhook_url, nous y envoyons un POST dès que la tâche se termine : plus besoin d’interroger l’API.

En-têteValeur
Content-Typeapplication/json
User-AgentTemplateFox-Webhook/1.0
X-TemplateFox-Eventpdf.completed ou pdf.failed
X-TemplateFox-TimestampHorodatage Unix, en secondes
X-TemplateFox-Signaturesha256=<hex>, uniquement si webhook_secret est défini
{
"event": "pdf.completed",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result": {
"url": "https://cdn.templatefox.com/generated/abc123/invoice-001.pdf",
"filename": "invoice-001.pdf"
}
}

Pour un envoi vers S3, l’objet result contient s3_bucket et s3_key à la place de url.

{
"event": "pdf.failed",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"error": {
"message": "Template rendering failed",
"code": "GENERATION_ERROR"
}
}

error.code vaut GENERATION_ERROR (échec du rendu), UPLOAD_ERROR (échec de l’envoi du fichier) ou UNKNOWN_ERROR ; error.message décrit l’erreur. Les mêmes valeurs se retrouvent dans error_code et error_message quand vous interrogez la tâche.

Quand un webhook_secret est défini, chaque webhook est signé en HMAC-SHA256 :

signature = HMAC_SHA256(secret, timestamp + "." + raw_body)

Comparez le résultat à la valeur de X-TemplateFox-Signature, après le préfixe sha256=. Calculez la signature sur le corps brut de la requête, avant tout parsing JSON : la moindre resérialisation la rend invalide.

import hmac
import hashlib

def verify_signature(secret: str, timestamp: str, raw_body: bytes, signature_header: str) -> bool:
  if not signature_header.startswith("sha256="):
      return False
  received = signature_header.removeprefix("sha256=")
  expected = hmac.new(
      secret.encode("utf-8"),
      f"{timestamp}.{raw_body.decode('utf-8')}".encode("utf-8"),
      hashlib.sha256,
  ).hexdigest()
  return hmac.compare_digest(received, expected)

Une livraison de webhook est tentée 3 fois au plus, avec 1 seconde puis 5 secondes d’attente entre les tentatives :

  • Nouvelle tentative si le délai expire, si la connexion échoue ou si votre endpoint répond en 5xx.
  • Pas de nouvelle tentative sur une réponse 4xx (votre endpoint a refusé la requête).

Répondez avec un code 2xx pour accuser réception. Sans réponse au bout de 30 secondes, la tentative compte comme un échec.

Liste les tâches de votre équipe, avec pagination et filtre par statut.

Paramètre de requêteTypeDéfautDescription
limitinteger20Taille de la page (100 au maximum).
offsetinteger0Nombre de résultats à sauter.
statusstring—Filtre par statut : pending, processing, completed ou failed.
curl "https://api.templatefox.com/v1/pdf/jobs?status=failed&limit=50" \
-H "x-api-key: YOUR_API_KEY"
{
"jobs": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"template_id": "HMQywVpZxqAM",
"export_type": "url",
"created_at": "2026-04-24T12:00:00Z",
"error_message": "Template rendering failed",
"error_code": "GENERATION_ERROR"
}
],
"total": 3,
"limit": 50,
"offset": 0
}
create-pdf (synchrone)create-pdf-async
Documents courts, données simplesGros documents ou rendus lourds
Échange requête-réponse interactifLots ou traitements en arrière-plan
Octets du PDF reçus directementNotification par webhook
Faible volume, un PDF par requêteGros volume, générations en parallèle