Passer au contenu
Développeurs

Intégrez en quelques minutes

Un SDK PHP sans dépendance : créez des factures, redirigez vers le paiement hébergé et vérifiez les webhooks signés. REST est disponible pour n'importe quel langage.

API en un coup d'œil
  • URL de baseapi.payora.money
  • AuthentificationHMAC-SHA256
  • FormatJSON · HTTPS
  • SDKsPHP · Node.js · Python
  • SpécificationOpenAPI 3.0
démarrage rapide

De la facture au webhook

  1. 01

    Créer une facture

    Un appel API avec un ID de commande et un montant en fiat ou en crypto renvoie une URL de paiement hébergée.

  2. 02

    Le client paie

    Ils choisissent une pièce, scannent le QR ou ouvrent un portefeuille, et le paiement est confirmé en direct à la finalité.

  3. 03

    Vous recevez un webhook signé

    Vérifiez la signature HMAC, créditez la commande une fois et regardez le paiement arriver sur votre solde.

SDK PHP

Un fichier, aucune dépendance. createInvoice(), getInvoice() et verifyWebhook() — intégrez-le dans n'importe quel projet.

Authentification HMAC

Les requêtes et les webhooks sont signés HMAC-SHA256 avec un décalage de timestamp et des clés d'idempotence.

API REST

JSON simple sur HTTPS — intégrez depuis n'importe quelle pile, pas seulement PHP.

checkout
<?php
require 'Payora.php';
$payora = new Payora('https://api.payora.money', getenv('PAYORA_KEY'), getenv('PAYORA_SECRET'));

// 1 — create an invoice (fiat-priced; the payer picks a coin)
$inv = $payora->createInvoice([
  'order_id'   => 'ORDER-42',
  'mode'       => 'fiat',
  'amount'     => '9.99',
  'return_url' => 'https://shop.example/thanks',
  'lang'       => 'en',
], 'ORDER-42'); // Idempotency-Key: a retry never creates a second invoice
header('Location: ' . $inv['pay_url']);

// 2 — webhook endpoint: ALWAYS verify the signature first
$event = $payora->verifyWebhook(file_get_contents('php://input'), getallheaders());
if ($event === null) { http_response_code(400); exit; }
if ($event['status'] === 'paid') {
  creditOrderOnce($event['id'], $event['order_id'], $event['amount'], $event['currency']);
}
http_response_code(200); // 2xx stops retries

Obtenez votre clé API et votre secret en créant un compte. Le SDK complet est dans votre tableau de bord.

authentification

Authentification

Chaque appel sauf /v1/health comporte trois en-têtes signés. La signature prouve que la demande provient du détenteur de votre api_secret et n'a pas été modifiée en cours de route.

En-têteValeurDescription
X-Payora-Keypk_…Votre clé api_key publique. Identifie le magasin.
X-Payora-Timestampunix secondsLe moment où vous avez signé la demande, en secondes Unix.
X-Payora-Signaturehex · 64HMAC-SHA256 hex en minuscules de timestamp + "." + corps brut, clé avec votre api_secret.
X-Payora-Test1Marque une facture comme un test de votre intégration : elle est réelle et peut recevoir des pièces, mais reste en dehors des rapports de demande et de conversion.
Idempotency-KeystringOptionnel sur POST /v1/invoice et POST /v1/payout. Une nouvelle tentative avec la même clé renvoie le premier résultat au lieu de créer un duplicata ; la même clé avec un corps différent répond 409.
Content-Typeapplication/jsonRequis sur les demandes qui contiennent un corps.
X-Payora-Signature=hex( HMAC-SHA256( api_secret, timestamp + "." + raw_body ) )

Signez les octets exacts que vous envoyez. La ré-encodage du JSON après la signature — même le réarrangement des clés ou l'ajout d'un espace — casse la signature.

Pour une requête GET, le corps est vide, donc la chaîne signée est le timestamp suivi d'un point.

L'API rejette un timestamp à plus de 120 secondes de son horloge. Gardez votre serveur synchronisé avec NTP.

Gardez api_secret sur votre serveur. Il signe les demandes et les webhooks : quiconque le détient peut créer des factures en votre nom et falsifier des rappels.

sign-request
<?php
$body = json_encode(['order_id' => 'ORDER-42', 'mode' => 'fiat', 'amount' => '9.99'], JSON_UNESCAPED_SLASHES);
$ts   = (string) time();
$sig  = hash_hmac('sha256', $ts . '.' . $body, $apiSecret); // lowercase hex

$ch = curl_init('https://api.payora.money/v1/invoice');
curl_setopt_array($ch, [
  CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'X-Payora-Key: ' . $apiKey,
    'X-Payora-Timestamp: ' . $ts,
    'X-Payora-Signature: ' . $sig,
    'Idempotency-Key: ORDER-42',
    'Content-Type: application/json',
  ],
]);
$invoice = json_decode(curl_exec($ch), true);
POST /v1/invoice

Paramètres de la facture

Tout est optionnel sauf order_id et amount. Le mode fiat permet au payeur de choisir n'importe quelle pièce activée sur votre compte ; le mode crypto nécessite également currency.

ParamètreTypeDescription
order_idstring · requiredVotre référence de commande unique (≤190 caractères). Une répétition est rejetée avec 409 — sécurisé contre les soumissions doubles.
amountstring · requiredMontant fiat (mode=fiat) ou montant crypto exact (mode=crypto).
modefiat | cryptoFiat par défaut : taux verrouillé par pièce au moment du paiement. La crypto fixe la pièce + le montant à l'avance.
fiat_currencystringCode fiat ISO pour le mode fiat (par défaut USD).
currencystringMonnaie pour le mode crypto (par exemple, TON, TRX, USDT_TRON).
return_urlhttps URLOù le bouton “Retour au magasin” du paiement renvoie le client — votre site. Absolument http(s) seulement.
langen·ru·uk·es·deLangue du paiement, afin qu'un client de votre magasin russe voie le paiement russe — pas en anglais. Également définissable comme ?lang=ru sur l'URL de paiement.
ttlsecondsCombien de temps la facture reste payable (120–86400 secondes, par défaut 1800).
customer_emailemailOptionnel — reçu + envoyé par e-mail au payeur.
notesstringNote librement formulée stockée sur la facture.

return_url et lang fonctionnent également comme paramètres de requête ajoutés à pay_url que l'API vous fournit — <pay_url>&lang=ru&return_url=https://shop.example/thanks. Envoyez toujours l'acheteur vers le pay_url retourné par l'API : il contient un jeton d'accès unique par facture, donc une page de paiement ne peut pas être atteinte en devinant les numéros de facture. Ne reconstruisez pas le lien à partir de l'identifiant de la facture.

Constructeur de requêtes

Construire une demande de facture signée

Remplissez les champs et copiez une commande cURL prête à l'emploi. Elle se signe elle-même dans votre shell avec $PAYORA_KEY et $PAYORA_SECRET — cette page ne voit jamais vos clés et n'envoie rien.

mode
POST /v1/invoice
BODY='{"order_id":"ORDER-42","mode":"fiat","amount":"9.99","fiat_currency":"USD","return_url":"https://shop.example/thanks","lang":"fr","ttl":1800}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$PAYORA_SECRET" | cut -d' ' -f2)

curl -X POST https://api.payora.money/v1/invoice \
  -H "X-Payora-Key: $PAYORA_KEY" \
  -H "X-Payora-Timestamp: $TS" \
  -H "X-Payora-Signature: $SIG" \
  -H 'Idempotency-Key: ORDER-42' \
  -H 'Content-Type: application/json' \
  -d "$BODY"

Rien n'est envoyé depuis cette page.

webhooks

Webhooks

Lorsqu'une facture ou un paiement change d'état, Payora envoie un événement JSON signé à votre URL de rappel. Vérifiez d'abord la signature, créditez la commande une fois, répondez 2xx.

ÉvénementstatusQuand il se déclenche
invoice.paidpaidLe paiement est confirmé sur la chaîne. Contient le montant, la pièce et tx_hash.
invoice.underpaidunderpaidLa facture a expiré après que moins que le montant attendu soit arrivé.
invoice.expiredexpiredLa facture a expiré sans rien reçu.
invoice.cancelledcancelledLa facture a été annulée. L'argent qui était déjà arrivé, le cas échéant, est décrit dans l'événement.
invoice.cancel_settled—L'argent qui est arrivé sur une facture annulée a été traité : crédité ou renvoyé.
invoice.late_payment—Argent arrivé sur une facture après son annulation. Envoyé une fois pour chaque dépôt de ce type ; le résultat indique s'il a été crédité ou s'il est en cours de retour.
payout.sentsentUn lot de paiements a été signé et diffusé. Contient chaque élément avec son tx_hash.

En-têtes de chaque livraison

En-têteValeurDescription
X-Payora-IduuidIdentifiant d'événement unique, le même que l'id dans le corps. Conservez-le pour ignorer les répétitions.
X-Payora-Eventinvoice.paidNom de l'événement.
X-Payora-Timestampunix secondsQuand cette tentative a été signée.
X-Payora-Signaturehex · 64Même schéma que les requêtes : HMAC-SHA256 de l'horodatage + "." + corps brut avec votre api_secret.

payload invoice.paid

ChampTypeDescription
iduuidID d'événement pour la dé-duplication.
eventstringNom de l'événement.
invoice_idintNuméro de facture Payora.
order_idstringVotre référence de commande, telle qu'envoyée lors de la création de la facture.
statusstringpaid pour invoice.paid.
currencystringMonnaie utilisée par le payeur, par exemple USDT_TRON.
amountdecimal stringMontant reçu.
amount_unitsinteger stringLe même montant dans les plus petites unités de la monnaie — utilisez-le pour des comparaisons exactes.
expecteddecimal stringMontant demandé par la facture.
fiat_amountdecimal string | nullPrix fiat de la facture tel que vous l'avez créée ; null pour les factures en mode crypto.
fiat_currencystring | nullCode ISO de fiat_amount ; null pour les factures en mode crypto.
tx_hashstringHash de transaction on-chain.
paid_atunix secondsQuand l'événement a été créé.
testbooltrue pour les factures sandbox.
invoice.paid
{
    "id": "6f1c2a4e-8b0d-4c1e-9a57-2f3d9e1b7c40",
    "event": "invoice.paid",
    "invoice_id": 1042,
    "order_id": "ORDER-42",
    "status": "paid",
    "currency": "USDT_TRON",
    "amount": "9.99",
    "amount_units": "9990000",
    "expected": "9.99",
    "fiat_amount": "9.99",
    "fiat_currency": "USD",
    "tx_hash": "3f9a…c21e",
    "paid_at": 1758038400,
    "test": false
}

Lorsque le montant reçu diffère de la facture, amount_received et amount_expected sont ajoutés.

Livraison et réessais

Tout ce qui n'est pas 2xx, ou pas de réponse dans les 15 secondes, est réessayé avec un backoff exponentiel plafonné à une heure entre les tentatives — jusqu'à 12 tentatives. Chaque tentative est signée à nouveau avec un nouvel horodatage ; le corps et l'ID d'événement restent les mêmes, donc dé-duplication par ID.

Après la dernière tentative, l'événement est marqué comme échoué et le propriétaire du magasin reçoit un e-mail. Les redirections ne sont jamais suivies, et l'URL de rappel doit être accessible depuis Internet — pas d'adresses localhost ou privées.

Avant de créditer une commande

  • Lisez le corps brut avant tout parsing JSON.
  • Recalculez la signature et comparez en temps constant : hash_equals, crypto.timingSafeEqual, hmac.compare_digest.
  • Rejetez les horodatages en dehors de votre fenêtre — les SDK acceptent ±300 secondes.
  • Vérifiez le statut et le montant par rapport à votre commande, puis créditez une fois par ID d'événement.
  • Répondez 2xx rapidement et effectuez un travail lent après avoir répondu.
webhook
<?php
require 'Payora.php';
$payora = new Payora('https://api.payora.money', getenv('PAYORA_KEY'), getenv('PAYORA_SECRET'));

$raw   = file_get_contents('php://input');           // raw, before any parsing
$event = $payora->verifyWebhook($raw, getallheaders()); // HMAC + ±300 s window, constant-time
if ($event === null) { http_response_code(400); exit; } // bad / forged / stale

if ($event['event'] === 'invoice.paid' && !alreadyProcessed($event['id'])) {
  creditOrder($event['order_id'], $event['amount'], $event['currency'], $event['tx_hash']);
  rememberProcessed($event['id']);
}
http_response_code(200); // 2xx stops retries
Playground

Terrain de jeu de signature de webhook

Entrez un secret, un timestamp et le corps brut pour voir la signature exacte que Payora enverrait — ou vérifiez-en une que vous avez reçue.

S'exécute dans votre navigateur avec WebCrypto. Rien de ce que vous tapez ne quitte cette page. Utilisez un secret de test, pas un secret en direct, sur un ordinateur partagé.

X-Payora-Timestamp
Chaîne signée
1758038400.{…}
En-têtes envoyés par Payora
headers
X-Payora-Timestamp: 1758038400
X-Payora-Signature: …

Collez une signature à comparer

paiements de masse

API de paiement de masse

Envoyez des cryptomonnaies à jusqu'à 500 portefeuilles dans une seule demande signée et idempotente — pour payroll, paiements d'affiliation ou retraits. Le total du lot plus les frais par article est immédiatement retenu sur votre solde interne ; le opérateur signe et diffuse, puis un webhook signé payout.sent se déclenche. Même authentification HMAC que pour tout le reste.

payout
# create a payout batch — funds held instantly, sent by the operator
curl -X POST https://api.payora.money/v1/payout \
  -H 'X-Payora-Key: pk_…' -H 'X-Payora-Timestamp: 1700000000' \
  -H 'X-Payora-Signature: <hmac-sha256>' -H 'Idempotency-Key: payroll-2026-01' \
  -d '{"currency":"USDT_TRON","items":[
        {"address":"TR7…","amount":"250.00"},
        {"address":"TX9…","amount":"99.50","tag":"batch-A"}]}'

# → 201 Created
{ "batch_id": 812, "status": "pending", "currency": "USDT_TRON",
  "item_count": 2, "total": "349.50", "fee": "…", "items": [ … ] }

# poll status, or receive a signed payout.sent webhook when it is sent
curl https://api.payora.money/v1/payout/812 -H 'X-Payora-Key: …' …

La validation est stricte : toute mauvaise adresse ou montant trop précis rejette l'ensemble du lot (HTTP 422) avec les index des éléments fautifs — un traitement de paie ne supprime jamais silencieusement un destinataire. Annulez un lot encore en attente avec POST /v1/payout/{id}/cancel pour libérer la retenue. Voir le article sur l'architecture.

référence

Référence de point de terminaison

Chaque point de terminaison parle JSON simple sur HTTPS à api.payora.money. Tous sauf /v1/health utilisent la même authentification de requête HMAC-SHA256. La spécification lisible par machine se trouve à openapi.json.

Point de terminaisonAccèsDescription
GET/v1/healthno authStatut du service plus la liste des devises activées.
POST/v1/invoiceauthCréez une facture (mode fiat ou crypto). Prend en charge Idempotency-Key. Renvoie 201 avec invoice_id, status, pay_url et expires ; le mode crypto ajoute l'adresse, le montant et le lien profond.
GET/v1/invoice/{id}authStatut de la facture (propres factures uniquement) : status, remaining, et le charge — devise, adresse, montants attendus/reçus et tx_hash.
POST/v1/payoutauth · Pro+Créez un lot de paiement de masse (validation stricte, fonds retenus instantanément). Prend en charge Idempotency-Key. Renvoie 201 avec la vue du lot : batch_id, status, totaux, frais, articles.
GET/v1/payoutauthListez vos lots de paiements récents (?limit=, par défaut 50).
GET/v1/payout/{id}authStatut du lot de paiements et éléments (propres lots uniquement).
POST/v1/payout/{id}/cancelauthAnnulez un lot encore en attente et libérez le solde retenu. Renvoie 409 si le lot n'est plus annulable.
téléchargements

SDK et téléchargements

Fichiers uniques sans dépendances. Chaque SDK signe les requêtes et vérifie les webhooks de la même manière.

phpPHPPayora.php

PHP 7.4+ avec cURL, un fichier. createInvoice, getInvoice et verifyWebhook.

jsNode.jspayora.js

Node.js avec https et crypto intégrés uniquement. Factures, solde, paiements et verifyWebhook.

pyPythonpayora.py

Bibliothèque standard Python uniquement. Factures, solde, paiements et verify_webhook.

{ }Postmanpayora.postman_collection.json

Une collection Postman qui signe chaque appel pour vous.

{…}OpenAPI 3.0openapi.json

La spécification lisible par machine de chaque point de terminaison, pour les générateurs de code et les clients API.

api.payora.moneyOuvrir
Utilisez-vous WooCommerce, WHMCS, Magento ou un autre CMS ?

Un module prêt fait tout cela pour vous : facture, redirection et un webhook vérifié.

Parcourir les plugins
FAQ

Questions fréquemment posées

Réponses directes, y compris les inconfortables : garde, frais et que se passe-t-il quand quelque chose ne va pas.

Centre d'aide

Comment intégrer Payora ?

Installez le SDK PHP en un seul fichier (sans dépendances) ou appelez directement l'API REST. Créez une facture avec createInvoice(), redirigez le client vers son pay_url et gérez un événement webhook : status=paid. Un développeur compétent est opérationnel en 30 à 60 minutes.

Y a-t-il une API REST pour des stacks non-PHP ?

Oui. Tout est du JSON simple sur HTTPS, donc vous pouvez intégrer depuis n'importe quel langage. Le SDK PHP est un wrapper pratique autour des mêmes points de terminaison — créer une facture, obtenir une facture et vérifier les signatures des webhooks.

Le client peut-il revenir sur mon site après avoir payé, dans la bonne langue ?

Oui. Passez return_url lorsque vous créez la facture (ou ?return_url= sur le lien de paiement) et le processus de paiement affiche un bouton « Retour au magasin » vers votre site sur l'écran de succès — et pendant le paiement. Passez lang (en, ru, uk, es, de), ou ?lang= sur le lien, afin qu'un client de votre magasin russe atterrisse sur le processus de paiement russe au lieu de l'anglais. Les deux sont optionnels ; return_url doit être une URL http(s) absolue.

Comment l'authentification de l'API est-elle gérée ?

Les requêtes et les webhooks sont authentifiés avec HMAC-SHA256 sur le timestamp et le corps brut en utilisant votre api_secret, avec une fenêtre de décalage de ±120 secondes et des clés d'idempotence. Les signatures sont comparées en temps constant pour prévenir les attaques par temporisation.

Comment obtenir des clés API ?

Créez un compte gratuit. Votre api_key publique et votre api_secret secret apparaissent dans le tableau de bord, ainsi que le SDK téléchargeable et la référence complète des webhooks. Faites tourner les clés à tout moment depuis les paramètres.

Que contient la charge utile du webhook ?

Un événement JSON signé avec l'identifiant de la facture, votre order_id, le statut (par exemple payé), le montant et la devise, et un identifiant d'événement unique pour l'idempotence. Vérifiez toujours la signature avant de créditer une commande, puis enregistrez l'identifiant de l'événement pour éviter le double traitement lors des nouvelles tentatives.

Y a-t-il une API pour les paiements massifs en crypto ?

Oui. POST /v1/payout envoie des cryptomonnaies à jusqu'à 500 portefeuilles en une seule demande — un {adresse, montant, tag optionnel} par élément, dans n'importe quelle monnaie activée sur votre compte. Il utilise la même authentification HMAC-SHA256 et la clé d'idempotence que l'API de facturation, donc une demande réessayée ne crée jamais un lot en double. Le total du lot plus les frais par élément est réservé sur votre solde immédiatement ; l'opérateur signe et diffuse, puis un webhook de paiement signé est déclenché. La validation est stricte — toute adresse invalide ou montant trop précis rejette l'ensemble du lot (422) donc un traitement de paie ne laisse jamais tomber silencieusement un destinataire.

Comment automatiser la paie en crypto ou les paiements d'affiliation ?

Créez la liste des destinataires dans votre propre système, puis appelez POST /v1/payout une fois par exécution avec une Idempotency-Key stable (par exemple payroll-2026-01). Interrogez GET /v1/payout/{id} ou attendez le webhook payout.sent pour confirmer la livraison et enregistrer chaque tx hash. Soumettre le lot réserve des fonds mais ne les déplace pas par lui-même — l'opérateur signe et diffuse, donc rien ne sort simplement avec un appel API.

Obtenez vos clés API

Un SDK PHP sans dépendance : créez des factures, redirigez vers le paiement hébergé et vérifiez les webhooks signés. REST est disponible pour n'importe quel langage.

Ce que cette page répond