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.

Vous utilisez WooCommerce, PrestaShop ou Magento ? Inutile d’écrire une ligne de code : une extension existe pour chacun. Suivez le tutoriel d’installation pas à pas, de la clé d’API au paiement de test.

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",
    "payer_email": "client@exemple.fr"
  }'

Réponse :

{
  "id": "b3f1…",
  "status": "pending",
  "amount_cents": 250000,
  "currency": "EUR",
  "reference": "CMD-1042",
  "payment_url": "https://app.virevo.fr/p/…",
  "test": false,
  "created_at": "2026-06-24T09:00:00.000Z",
  "expires_at": "2026-07-01T09:00:00.000Z",
  "payer_email": "client@exemple.fr",
  "due_date": null,
  "payer_is_business": false,
  "send_email": false,
  "emails_sent": 0,
  "settled_elsewhere": false
}

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. Minimum 100 (1 €), maximum 10 000 000. En dessous, erreur AMOUNT_BELOW_MINIMUM.
currencyEUR.
referenceVotre référence de commande (sert au rapprochement), 140 caractères au plus. Sur le relevé bancaire du client, elle apparaît sans accents, limitée à 50 caractères, et les caractères comme / y deviennent des espaces.
payer_emailOptionnel. E-mail de votre client : il n'a pas à le saisir pendant le paiement, et il peut mémoriser son compte bancaire pour ses paiements suivants chez vous.
return_urlOptionnel. Redirection du client après paiement réussi (avec ?virevo_payment_id&status=succeeded&reference).
cancel_urlOptionnel. Redirection du client si le paiement échoue ou est annulé (avec ?virevo_payment_id&status=failed ou canceled&reference). À défaut, return_url. Adresses en https:// uniquement.
due_dateOptionnel. Échéance d'une facture, AAAA-MM-JJ, entre aujourd'hui et dans 120 jours. Le lien reste alors valable 180 jours (cf. ci-dessous).
send_emailOptionnel, false par défaut. Virevo envoie le lien à payer_email (obligatoire dans ce cas) dès la création, puis le relance.
payer_is_businessOptionnel. Avec due_date : votre client est un professionnel, le dernier rappel cite les pénalités de retard et l'indemnité forfaitaire de 40 €.

Encaisser une facture (logiciels de facturation)

Transmettez l'échéance et l'e-mail du client : Virevo envoie la facture, relance le client, et vous prévient si elle reste impayée. Vous n'avez rien d'autre à gérer.

curl -X POST https://app.virevo.fr/v1/payments \
  -H "Authorization: Bearer vrv_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: facture-FA-2026-0412" \
  -d '{
    "amount_cents": 45000,
    "reference": "Facture FA-2026-0412",
    "payer_email": "compta@client.fr",
    "due_date": "2026-11-30",
    "send_email": true,
    "payer_is_business": true
  }'
Avec send_emailE-mails au payeur
Avec due_dateLa facture à la création, puis des rappels 3 jours avant l'échéance, le jour même, puis à 7, 15 et 30 jours de retard. Une semaine après le dernier, vous êtes prévenu par e-mail ; le lien reste payable jusqu'à son expiration.
Sans due_dateLe lien à la création, puis deux relances à J+3 et J+6. S'il expire sans paiement (7 jours), vous êtes prévenu.
Les relances s'arrêtent d'elles-mêmes au paiement, à l'annulation, ou si la facture est réglée autrement (chèque, virement classique) : déclarez-le avec settled_elsewhere (voir « Annuler un paiement »). Le champ emails_sent compte les envois. Placez payment_url sur votre facture (lien ou QR code) : c'est la même page que dans les e-mails.
Pour une facture, un refus de la banque du client n'est pas définitif : il peut réessayer depuis le même lien. Le paiement reste donc pending et aucun payment.failed n'est émis. En mode test, l'échéance et la durée du lien sont appliquées, mais aucun e-mail ne part (send_email revient à false).

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é par la banque du client. Définitif : le lien n'accepte pas de nouvelle tentative. Si votre client veut réessayer, créez un nouveau paiement. Exception : une facture (due_date ou send_email), que le client peut réessayer depuis le même lien.
canceledAnnulé par vous (settled_elsewhere indique une facture réglée hors Virevo), ou expiré : un lien de paiement est valable 7 jours, 180 jours avec due_date (date exacte dans expires_at).
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.

Annuler un paiement

Un paiement encore pending peut être annulé : le lien cesse de fonctionner et l'événement payment.canceled est émis.

curl -X POST https://app.virevo.fr/v1/payments/{id}/cancel \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

# facture réglée hors Virevo (chèque, virement classique) : mêmes effets,
# mais le paiement porte settled_elsewhere: true
curl -X POST https://app.virevo.fr/v1/payments/{id}/cancel \
  -H "Authorization: Bearer vrv_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"settled_elsewhere": true}'
Si votre client est déjà passé par sa banque, l'annulation est refusée (409 PAYMENT_TRANSFER_IN_PROGRESS) : son virement peut encore aboutir, et l'annuler le rendrait invisible. Attendez le webhook. Un paiement qui règle une échéance ne s'annule pas seul : annulez l'échéancier (§6).

Remboursements

Pas encore disponibles en paiement réel. Notre partenaire bancaire ne propose pas encore le virement retour : avec une clé live, la création renvoie une erreur. En attendant, remboursez votre client par un virement depuis votre banque. Les routes fonctionnent en mode test, pour préparer votre intégration.

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.

Les échéanciers (§6) ne sont pas disponibles en mode test : chaque échéance envoie un vrai e-mail à votre client.

5. Webhooks

Enregistrez l'URL de votre serveur dans le dashboard → Développeurs. Vous recevez un secret (whsec_…). Événements émis : payment.succeeded, payment.failed, payment.canceled, payment.expired, payment.refunded, et pour les échéanciers installment.paid, installment.unpaid, installment_plan.completed, installment_plan.canceled (§6). À chaque encaissement, Virevo envoie :

Traitez les quatre, pas seulement le succès. failed, canceled et expired sont les trois façons dont un paiement se termine sans argent. Une intégration qui ne guette que payment.succeeded laisse ses commandes « en attente » indéfiniment, et son stock réservé avec elles.
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",
    "created_at": "2026-06-24T09:00:00.000Z",
    "due_date": null, "settled_elsewhere": false
  } }
}

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.

6. Échéanciers (paiement en plusieurs fois)

Vous fixez les échéances, Virevo s'occupe du reste : le jour de chaque échéance, votre client reçoit par e-mail son lien de paiement, puis une relance à J+3 et J+7. Il peut essayer jusqu'à 3 fois si sa banque refuse. Sans paiement à J+14, l'échéance est déclarée impayée et vous êtes prévenu.

curl -X POST https://app.virevo.fr/v1/installment_plans \
  -H "Authorization: Bearer vrv_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: devis-207" \
  -d '{
    "reference": "Devis 207",
    "payer": { "name": "Marie Martin", "email": "marie@exemple.fr" },
    "installments": [
      { "amount_cents": 50000, "due_date": "2026-10-10" },
      { "amount_cents": 50000, "due_date": "2026-11-10" },
      { "amount_cents": 50000, "due_date": "2026-12-10" }
    ]
  }'

Réponse (même forme pour la lecture, la liste et l'annulation) :

{
  "id": "5a9c…",
  "status": "active",
  "reference": "Devis 207",
  "payer": { "name": "Marie Martin", "email": "marie@exemple.fr" },
  "total_cents": 150000,
  "paid_cents": 0,
  "currency": "EUR",
  "created_at": "2026-10-03T10:00:00.000Z",
  "installments": [
    { "id": "e1…", "seq": 1, "amount_cents": 50000, "due_date": "2026-10-10",
      "status": "scheduled", "rejections": 0,
      "payment_url": "https://app.virevo.fr/e/…", "paid_at": null },
    …
  ]
}
RègleDétail
Nombre d'échéancesDe 2 à 12.
Montant1 € minimum par échéance (amount_cents ≥ 100).
Datesdue_date au format AAAA-MM-JJ, strictement croissantes, la première pas avant aujourd'hui.
CommissionDue sur chaque échéance réglée, comme un paiement ordinaire, et facturée au mois.
# lire
curl https://app.virevo.fr/v1/installment_plans/{id} \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

# lister (curseur, comme les paiements)
curl "https://app.virevo.fr/v1/installment_plans?limit=20&starting_after={id}" \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"

# annuler : les échéances non réglées ne sont plus envoyées ni relancées
curl -X POST https://app.virevo.fr/v1/installment_plans/{id}/cancel \
  -H "Authorization: Bearer vrv_live_xxxxxxxx"
Statut d'une échéanceSignification
scheduledDate à venir, rien n'a encore été envoyé.
dueLien envoyé, en attente de paiement.
paidRéglée.
unpaid3 refus de la banque, ou rien reçu 14 jours après la date. Un virement tardif peut encore la régler.
canceledÉchéancier annulé.

L'échéancier lui-même est active, puis completed quand plus aucune échéance n'est à venir, ou canceled.

Webhooks d'échéancier

ÉvénementQuand
installment.paidUne échéance est réglée.
installment.unpaidUne échéance est déclarée impayée.
installment_plan.completedPlus aucune échéance à venir.
installment_plan.canceledL'échéancier est annulé.
{
  "id": "evt_…",
  "type": "installment.paid",
  "created_at": "2026-10-10T09:12:00.000Z",
  "data": {
    "installment_plan": { "id": "5a9c…", "status": "active", … },
    "installment": { "id": "e1…", "seq": 1, "status": "paid", … }
  }
}
Les événements d'échéance partent au passage de traitement suivant le règlement, sous 5 minutes. Les tentatives de paiement d'une échéance n'émettent pas d'événement payment.* : un refus n'y est pas définitif, puisque votre client peut réessayer.

7. Erreurs

Toute erreur renvoie un code HTTP et un corps {"error": {"code": "…", "message": "…"}}. Le message est en français et peut être montré tel quel ; basez votre logique sur code.

HTTPCodeCause
400VALIDATION_ERRORChamp manquant ou invalide (le détail est dans details).
400AMOUNT_BELOW_MINIMUMMontant inférieur à 1 €.
400INSTALLMENT_DATE_PASTPremière échéance datée d'avant aujourd'hui.
401UNAUTHORIZEDClé d'API absente, invalide ou révoquée.
402INVOICE_UNPAIDFacture Virevo impayée depuis plus de 15 jours : réglez-la depuis le dashboard. Les paiements déjà créés aboutissent normalement.
403MANDATE_REQUIREDPrélèvement de la commission pas encore autorisé : une case à cocher dans le dashboard. Les paiements déjà créés aboutissent normalement.
403KYC_NOT_VERIFIEDCompte pas encore vérifié. Le mode test reste disponible.
403IBAN_NOT_VERIFIEDTitulaire de l'IBAN à vérifier.
403PROVIDER_KYC_NOT_VERIFIEDVérification par notre partenaire bancaire en cours, en général quelques minutes après la validation du compte.
403ACCOUNT_CLOSEDCompte résilié.
404PAYMENT_NOT_FOUND, INSTALLMENT_PLAN_NOT_FOUNDIdentifiant inconnu, ou d'un autre compte.
409CONFLICTIdempotency-Key déjà utilisée avec d'autres paramètres.
409PAYMENT_NOT_CANCELLABLE, PAYMENT_TRANSFER_IN_PROGRESSAnnulation impossible (§3).
429RATE_LIMITEDTrop de requêtes : 120 créations de paiement par minute au plus.
502BRIDGE_UNAVAILABLEPartenaire bancaire momentanément injoignable : réessayez avec la même Idempotency-Key.

Référence complète

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