Virevo ← Retour
API développeurs

Encaissez par virement instantané depuis votre site

Une API REST pour intégrer Virevo à un site sur mesure ou un plugin CMS : créez un paiement, redirigez le client, recevez un webhook signé à l'encaissement.

Base URL : https://app.virevo.fr · Référence détaillée par endpoint : Référence API.

1. Authentification

Créez une clé d'API depuis votre dashboard → Développeurs. Deux modes : vrv_test_… (bac à sable, paiements fictifs) et vrv_live_… (réel). Passez-la en en-tête sur chaque appel /v1 :

Authorization: Bearer vrv_live_xxxxxxxx
La clé n'est affichée qu'une fois à la création. Stockez-la côté serveur, jamais dans du code client.

2. Créer un paiement

curl -X POST https://app.virevo.fr/v1/payments \
  -H "Authorization: Bearer vrv_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: commande-1042" \
  -d '{
    "amount_cents": 250000,
    "currency": "EUR",
    "reference": "CMD-1042",
    "return_url": "https://votre-site.fr/merci",
    "cancel_url": "https://votre-site.fr/panier"
  }'

Réponse :

{
  "id": "b3f1…",
  "status": "pending",
  "amount_cents": 250000,
  "currency": "EUR",
  "reference": "CMD-1042",
  "payment_url": "https://app.virevo.fr/pay/…",
  "test": false,
  "created_at": "2026-06-24T09:00:00.000Z"
}

Redirigez ensuite le client vers payment_url pour qu'il valide le virement. L'Idempotency-Key (recommandée) garantit qu'un même envoi ne crée pas deux paiements.

ChampDescription
amount_centsMontant en centimes (entier, max 10 000 000).
currencyEUR.
referenceVotre référence de commande (sert au rapprochement).
return_urlOptionnel. Redirection du client après paiement réussi (avec ?virevo_payment_id&status=succeeded&reference).
cancel_urlOptionnel. Redirection si le client annule.

3. Suivre le statut

curl https://app.virevo.fr/v1/payments/b3f1… \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

Statuts possibles :

StatutSignification
pendingEn attente de règlement.
succeededVirement reçu, vous pouvez valider la commande.
failedRefusé.
canceledAnnulé / expiré.
Le moyen fiable d'être notifié n'est pas le polling, mais le webhook (§5).

Lister les paiements

Pagination par curseur. La liste est limitée au mode de votre clé (une clé test ne voit que les paiements de test). Paramètres : limit (1–100, défaut 20), starting_after (id du dernier élément reçu), status, from, to (dates ISO sur created_at).

curl "https://app.virevo.fr/v1/payments?limit=20&status=succeeded" \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

{
  "object": "list",
  "data": [ { "id": "b3f1…", "status": "succeeded", … } ],
  "has_more": true
}

# page suivante : reprendre à partir du dernier id reçu
curl "https://app.virevo.fr/v1/payments?limit=20&starting_after=b3f1…" \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"
Tant que has_more vaut true, redemandez avec starting_after = id du dernier élément.

Remboursements

Créez un remboursement (total ou partiel) sur un paiement réglé, puis relisez-les. Idempotency-Key recommandé sur la création (un rejeu ne crée pas de doublon). Émet l'événement payment.refunded.

# créer (montant en centimes ; sans amount_cents = solde restant)
curl -X POST https://app.virevo.fr/v1/payments/{id}/refund \
  -H "Authorization: Bearer vrv_live_xxxxxxxx" \
  -H "Idempotency-Key: refund-cmd-1042" \
  -H "Content-Type: application/json" \
  -d '{"amount_cents": 2000, "reason": "geste commercial"}'

# lister les remboursements d'un paiement
curl https://app.virevo.fr/v1/payments/{id}/refunds \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"
# → { "object": "list", "data": [ { "id": "ref_…", "amount_cents": 2000, … } ] }

# relire un remboursement par id
curl https://app.virevo.fr/v1/refunds/{refund_id} \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

4. Mode test (sans compte vérifié)

Avec une clé vrv_test_…, les paiements sont fictifs (aucun KYC, aucun mouvement réel). Pour simuler un encaissement et déclencher le webhook :

curl -X POST https://app.virevo.fr/v1/payments/{id}/simulate \
  -H "Authorization: Bearer vrv_test_xxxxxxxx"
# → status: "succeeded" + envoi du webhook payment.succeeded

Vous pouvez ainsi développer toute votre intégration de bout en bout avant la mise en production.

5. Webhooks

Enregistrez l'URL de votre serveur dans le dashboard → Développeurs. Vous recevez un secret (whsec_…). Événements émis : payment.succeeded, payment.refunded, payment.canceled. À chaque encaissement, Virevo envoie :

Le bouton « Envoyer un test » (dashboard → Développeurs) émet un événement webhook.test signé vers votre URL, pour valider votre intégration sans créer de paiement. Votre handler doit ignorer les types d'événements inconnus (dont webhook.test).
Un endpoint qui échoue 10 fois de suite est automatiquement désactivé (on cesse d'envoyer pour ne pas marteler un serveur indisponible) et vous êtes prévenu par email. Réactivez-le depuis le dashboard une fois corrigé : le compteur d'échecs repart à zéro.
POST https://votre-site.fr/virevo/webhook
Virevo-Signature: t=1750000000,v1=<hmac-sha256>
Virevo-Event-Type: payment.succeeded

{
  "id": "evt_…",
  "type": "payment.succeeded",
  "created_at": "2026-06-24T09:01:00.000Z",
  "data": { "payment": {
    "id": "b3f1…", "status": "succeeded",
    "amount_cents": 250000, "currency": "EUR", "reference": "CMD-1042"
  } }
}

Vérifier la signature

La signature est un HMAC-SHA256 de "{t}.{corps_brut}" avec votre secret. Recalculez-la et comparez à v1 ; rejetez si l'écart de temps dépasse 5 minutes (anti-rejeu). L'en-tête peut contenir plusieurs v1 (pendant une rotation de secret, cf. §5.1) : acceptez si l'un d'eux correspond.

PHP (WordPress / WooCommerce) :

$payload = file_get_contents('php://input');
$sig = $_SERVER['HTTP_VIREVO_SIGNATURE'] ?? '';
$t = null; $sigs = [];
foreach (explode(',', $sig) as $part) {            // t=…,v1=…,v1=…
    [$k, $v] = array_pad(explode('=', $part, 2), 2, '');
    if (trim($k) === 't') $t = (int) trim($v);
    elseif (trim($k) === 'v1') $sigs[] = trim($v);
}
$expected = hash_hmac('sha256', $t . '.' . $payload, $secret);
$ok = false;
foreach ($sigs as $v1) { if (hash_equals($expected, $v1)) { $ok = true; break; } }
if (!$ok || $t === null || abs(time() - $t) > 300) {
    http_response_code(400); exit;
}
$event = json_decode($payload, true);
// $event['data']['payment']['reference'] → valider la commande

Node.js :

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, header, rawBody) {
  let t = NaN; const sigs = [];
  for (const kv of header.split(",")) {            // t=…,v1=…,v1=…
    const i = kv.indexOf("="); if (i < 0) continue;
    const k = kv.slice(0, i).trim(), v = kv.slice(i + 1).trim();
    if (k === "t") t = Number(v); else if (k === "v1") sigs.push(v);
  }
  const expected = createHmac("sha256", secret)
    .update(`${t}.${rawBody}`).digest("hex");
  const eb = Buffer.from(expected);
  const ok = sigs.some((v1) => v1.length === expected.length &&
    timingSafeEqual(eb, Buffer.from(v1)));
  return ok && Number.isFinite(t) && Math.abs(Date.now() / 1000 - t) <= 300;
}
Répondez 2xx rapidement. En cas d'erreur ou de timeout, Virevo réessaie (jusqu'à 6 fois, délai croissant).

5.1 Renouveler le secret (rotation)

Depuis le dashboard → Développeurs, le bouton « Renouveler le secret » génère un nouveau whsec_…. L'ancien reste valide 24 h : pendant cette fenêtre, Virevo signe chaque livraison avec les deux secrets (deux v1 dans l'en-tête). Vous pouvez donc déployer le nouveau secret sans aucune livraison perdue, du moment que votre vérification accepte l'un des v1 (code ci-dessus). Passé 24 h, seul le nouveau secret signe.

Référence complète

Détail de chaque endpoint (paramètres, corps, réponses, authentification) : Référence API.