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-asyncAuthentification : 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.
Fonctionnement
Section intitulée « Fonctionnement »- Vous appelez
POST /v1/pdf/create-asyncavec votretemplate_idet vosdata: vous recevez aussitôt unjob_id. - La tâche passe par
pending→processing→completedoufailed. - Le résultat vous parvient de deux façons (ou des deux) :
- Interrogation — appelez
GET /v1/pdf/jobs/{job_id}jusqu’à ce questatusvaillecompletedoufailed. - Webhook — passez une
webhook_urldans la requête : nous y envoyons un POST quand la tâche se termine.
- Interrogation — appelez
Les deux modes fonctionnent en même temps. Le webhook est facultatif.
Lancer une tâche
Section intitulée « Lancer une tâche »Champs obligatoires
Section intitulée « Champs obligatoires »| Champ | Type | Description |
|---|---|---|
template_id | string | L’identifiant du template, 12 caractères. |
data | object | Les 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#.
Tous les paramètres
Section intitulée « Tous les paramètres »| Champ | Type | Obligatoire | Défaut | Description |
|---|---|---|---|---|
template_id | string | ✅ | — | Identifiant du template, 12 caractères. |
data | object | ✅ | — | Les données clé-valeur injectées dans le template. |
export_type | string | — | "url" | En asynchrone, seule la valeur "url" est prise en charge pour l’instant. Pour une réponse binaire, utilisez create-pdf. |
expiration | integer | — | 86400 | Durée de validité de l’URL signée, en secondes (60 à 604800). |
filename | string | — | "document" | Nom de fichier personnalisé (sans extension). |
store_s3 | boolean | — | false | Envoie le fichier dans votre bucket S3 configuré plutôt que sur notre CDN. |
s3_filepath | string | — | — | Préfixe de chemin dans votre bucket S3. |
s3_bucket | string | — | — | Remplace le nom de bucket de votre intégration S3. |
webhook_url | string | — | — | 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_secret | string | — | — | Secret (16 à 256 caractères) qui sert à signer le contenu des webhooks en HMAC-SHA256. |
pdf_variant | string | — | — | "pdf/a-1b", "pdf/a-2b" ou "pdf/a-3b", pour un PDF conforme aux normes d’archivage. |
version | string | — | — | Tag ou numéro de version du template. |
Exemple : webhook signé et envoi vers S3
Section intitulée « Exemple : webhook signé et envoi vers S3 »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}| Champ | Type | Description |
|---|---|---|
job_id | string | UUID à interroger, ou à rapprocher des notifications webhook. |
status | string | Toujours "pending" à la création. |
credits_remaining | number | Crédits restants après le débit. |
Suivre l’état d’une tâche
Section intitulée « Suivre l’état d’une tâche »GET /v1/pdf/jobs/{job_id}
Section intitulée « GET /v1/pdf/jobs/{job_id} »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" Valeurs de statut
Section intitulée « Valeurs de statut »| Statut | Description |
|---|---|
pending | En file d’attente, pas encore pris en charge. |
processing | Le PDF est en cours de rendu. |
completed | Le PDF est prêt : voir result_url, ou result_s3_bucket / result_s3_key. |
failed | La 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}Rythme d’interrogation
Section intitulée « Rythme d’interrogation »- 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.
Webhooks
Section intitulée « Webhooks »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êtes
Section intitulée « En-têtes »| En-tête | Valeur |
|---|---|
Content-Type | application/json |
User-Agent | TemplateFox-Webhook/1.0 |
X-TemplateFox-Event | pdf.completed ou pdf.failed |
X-TemplateFox-Timestamp | Horodatage Unix, en secondes |
X-TemplateFox-Signature | sha256=<hex>, uniquement si webhook_secret est défini |
Contenu en cas de succès
Section intitulée « Contenu en cas de succès »{ "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.
Contenu en cas d’échec
Section intitulée « Contenu en cas d’échec »{ "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.
Vérifier la signature
Section intitulée « Vérifier la signature »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) Nouvelles tentatives
Section intitulée « Nouvelles tentatives »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.
Lister les tâches
Section intitulée « Lister les tâches »GET /v1/pdf/jobs
Section intitulée « GET /v1/pdf/jobs »Liste les tâches de votre équipe, avec pagination et filtre par statut.
| Paramètre de requête | Type | Défaut | Description |
|---|---|---|---|
limit | integer | 20 | Taille de la page (100 au maximum). |
offset | integer | 0 | Nombre de résultats à sauter. |
status | string | — | 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}Synchrone ou asynchrone
Section intitulée « Synchrone ou asynchrone »create-pdf (synchrone) | create-pdf-async |
|---|---|
| Documents courts, données simples | Gros documents ou rendus lourds |
| Échange requête-réponse interactif | Lots ou traitements en arrière-plan |
| Octets du PDF reçus directement | Notification par webhook |
| Faible volume, un PDF par requête | Gros volume, générations en parallèle |