Postback serveur à serveur
Suivez les conversions en appelant l'API REST directement depuis votre backend, sans le SDK.
Le SDK est le chemin recommandé pour les stacks JavaScript et TypeScript. Si vous êtes sur un autre runtime — PHP, Python, Ruby, Go, Elixir — ou si vous ne voulez pas de dépendance, appelez les endpoints REST publics directement. Ce guide couvre le pattern le plus utilisé : un postback serveur à serveur déclenché depuis votre backend de checkout après un paiement réussi.
Quand utiliser le postback
Le postback est le bon pattern quand :
- La conversion a lieu côté serveur (webhook Stripe, IPN PayPal, processeur de paiement custom).
- Vous avez besoin de garanties de livraison plus strictes que ce qu'un pixel navigateur peut offrir.
- Vous opérez sur une stack non-JS.
- La session navigateur peut être perdue entre le clic et la conversion (Safari ITP, cross-device, app mobile).
Si la conversion est liée à une page que le client est en train de visiter, le SDK est plus simple.
Endpoint
POST /api/v1/conversions/postback
Authorization: Bearer <VOTRE_CLE_API>
Content-Type: application/jsonPayload
{
"externalId": "ord_42",
"conversionType": "SALE",
"amount": 4990,
"currency": "EUR",
"sessionId": "rcs_7fKj2...",
"metadata": { "plan": "pro" }
}| Champ | Type | Requis | Notes |
|---|---|---|---|
externalId | string (1–255) | oui | Votre identifiant de commande / transaction. Sert de clé d'idempotence. |
conversionType | string | oui | L'un de SALE, LEAD, TRIAL, CUSTOM. |
amount | integer | oui | Valeur de la conversion en unités mineures (centimes). Ex. 49,90 € → 4990. Les décimaux sont rejetés avec 422. |
currency | string | oui | Code ISO 4217 à 3 lettres (mis en majuscules côté serveur). |
sessionId / rcsid | string | un parmi | Identifiant de session depuis le cookie de clic. Préféré quand intact. |
clickId / cid | string | un parmi | Identifiant de clic retourné par l'URL de tracking. Alternative à sessionId. |
customerEmailHash | string | un parmi | SHA-256 hex de l'email client en minuscules. Fallback si la session est perdue. |
customerEmail | string | un parmi | Email client en clair (hashé côté serveur). Fallback. |
customerId | string | non | Votre identifiant client interne. |
convertedAt | string | non | Datetime ISO 8601 de la conversion. Par défaut : maintenant. |
customParams | object | non | Jusqu'à 5 paramètres personnalisés : { s1, s2, s3, s4, s5 }. |
metadata | object | non | Format libre. Persisté sur la conversion, exposé dans les exports. |
Au moins un identifiant d'attribution (sessionId/rcsid, clickId/cid, customerEmailHash ou customerEmail) doit être présent. Si plusieurs sont fournis, la priorité est : clickId → sessionId → customerEmailHash → customerEmail.
Calculer le hash de l'email
Hashez côté serveur, pas côté client
Le hash est un identifiant de fallback ; si vous le calculez dans le navigateur, un attaquant peut le rejouer pour s'attribuer des conversions. Hashez toujours côté serveur, après avoir vérifié que l'email appartient bien au client qui paie.
import hashlib
email = customer_email.lower().strip()
email_hash = hashlib.sha256(email.encode()).hexdigest()$emailHash = hash('sha256', strtolower(trim($email)));require 'digest'
email_hash = Digest::SHA256.hexdigest(email.downcase.strip)Le hash est ce que nous stockons. L'email en clair ne quitte jamais votre infrastructure.
Exemple : handler webhook Stripe
Pattern typique : votre serveur reçoit déjà un webhook Stripe checkout.session.completed. Étendez le handler pour déclencher un postback RefCampaign.
# Python / Flask
import os
import requests
REFCAMPAIGN_KEY = os.environ['REFCAMPAIGN_API_KEY']
REFCAMPAIGN_URL = 'https://app.refcampaign.com/api/v1/conversions/postback'
def on_stripe_completed(session):
requests.post(
REFCAMPAIGN_URL,
headers={
'Authorization': f'Bearer {REFCAMPAIGN_KEY}',
'Content-Type': 'application/json',
},
json={
'externalId': session.id,
'conversionType': 'SALE',
'amount': session.amount_total, # déjà en centimes
'currency': session.currency.upper(),
},
timeout=10,
)Idempotence et retries
L'endpoint est idempotent sur externalId — un appel répété avec le même externalId pour le même marchand renvoie la conversion existante ({ success: true, conversionId, message: "Conversion already tracked" }) sans créer de doublon. Si le même externalId est soumis par un autre marchand, le serveur retourne 409.
Si votre handler webhook retry sur erreur transitoire, c'est sûr — renvoyer le même externalId ne crée jamais de conversion en double.
Pour les retries au niveau réseau : respectez le header Retry-After sur 429, traitez les 5xx comme transitoires avec backoff, traitez les 4xx comme terminaux (pas de retry, log + alerte).
Vérifier la livraison
Le tableau de bord marchand affiche les conversions entrantes en temps réel. Pour les pipelines automatisés, requêtez la liste des conversions pour confirmer l'arrivée :
curl https://app.refcampaign.com/api/v1/conversions?campaignId=cmp_xxx&limit=10 \
-H "Authorization: Bearer $REFCAMPAIGN_API_KEY"Sécurité
- Envoyez la clé API uniquement sur HTTPS.
- Stockez-la dans un gestionnaire de secrets — jamais dans le code source.
- Utilisez une clé dédiée par environnement (production / staging / local).
- Voir authentification pour la checklist complète.