Tout ce qu'il faut pour intégrer Paygride dans ton produit en 10 minutes.
curl https://app.paygride.com/api/v1/links \
-X POST \
-H "Authorization: Bearer sk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Pack Premium",
"currency": "XOF",
"accepted_networks": ["mtn", "moov"],
"amount": 5000
}'Crée un lien, encaisse sur la page hébergée, sois notifié côté serveur.
Renseigne au minimum un title, une currency et au moins un réseau dans accepted_networks. Glisse ton identifiant de commande dans external_reference : Paygride te le renvoie tel quel dans le webhook.
{
"id": "f3a1c0d2-…",
"slug": "pack-premium-x4z9",
"url": "https://app.paygride.com/pay/acme/pack-premium-x4z9",
"title": "Pack Premium",
"subtitle": null,
"amount": 5000,
"currency": "XOF",
"status": "active",
"accepted_networks": ["mtn", "moov"],
"expires_at": null,
"external_reference": "order_1234"
}Partage urltelle quelle, ou redirige l'acheteur dessus. Avec un domaine personnalisé (Paramètres → Domaines), l'URL est servie depuis ton sous-domaine.
Ne valide jamais un paiement sur la seule redirection navigateur : attends le webhook serveur-à-serveur. Enregistre ton endpoint dans Paramètres → Webhooks pour récupérer ton secret whsec_….
{
"id": "evt_3a7e2c91b88f1d4ce5b0a223",
"type": "payment.succeeded",
"created": 1717160521,
"data": {
"transaction": {
"id": "9b1c…",
"reference": "KDT-ABC123",
"provider_transaction_id": "fp_xyz",
"status": "succeeded",
"payment_link_slug": "pack-premium-x4z9",
"external_reference": "order_1234"
}
}
}import { createHmac, timingSafeEqual } from "node:crypto";
// secret = whsec_… (dashboard → Paramètres → Webhooks)
// rawBody = corps BRUT de la requête (string) — surtout pas JSON.parse puis re-stringify
// header = valeur du header X-Paygride-Signature, ex. "t=1717160521,v1=ab12…"
export function verifyPaygrideSignature(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(",").map((kv) => kv.trim().split("=", 2)),
);
const ts = Number(parts.t);
const v1 = parts.v1;
if (!ts || !v1) return false;
if (Math.abs(Date.now() / 1000 - ts) > 300) return false; // anti-replay 5 min
const expected = createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
return (
expected.length === v1.length &&
timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(v1, "hex"))
);
}Réconcilie sur external_reference (ton ID de commande) ou reference(l'ID Paygride). Réponds 2xxen moins de 10 s et traite l'event de façon idempotente (tu peux le recevoir plusieurs fois — l'idde l'event est stable).
Base URL : https://app.paygride.com/api/v1
Toutes les requêtes nécessitent un header Authorization: Bearer <clé>. Les clés sont créées depuis le dashboard, en mode test ou live. La clé secrète n'est affichée qu'au moment de la création - copie-la, on ne la stocke pas en clair.
curl https://app.paygride.com/api/v1/methods \
-H "Authorization: Bearer sk_live_xxxxxxxxxxxx"Chaque clé porte des scopes. read couvre les GET ; write est requis pour POST /v1/links et POST /v1/payouts. Un scope manquant renvoie 403.
100 requêtes/min par clé, 200/min par IP. Au-delà, la requête est rejetée en 401 — espace tes appels en cas de pic.
Les erreurs sont retournées au format { "error": "description courte" }.
Paygride POSTe un payload JSON signé HMAC SHA-256 sur ton URL à chaque event. Configure tes endpoints dans Paramètres → Webhooks.
La signature recompose <ts>.<raw_body> puis HMAC-SHA256 avec ton secret. Tolérance 5 min contre replay.
payment.succeededpayment.failedpayment.refundedpayout.processingpayout.paidpayout.failedpingRetry policy : 7 tentatives avec backoff exponentiel (1 min → 5 min → 30 min → 2 h → 12 h → 1 jour). Ton endpoint doit répondre 2xx en moins de 10 s. Au-delà, la delivery passe en abandoned (visible dans le dashboard).
Endpoints et outils en cours de développement.
Le fichier docs/PUBLIC_API.md est la source de vérité, mise à jour à chaque release.