SDK PHP
Un fichier, aucune dépendance. createInvoice(), getInvoice() et verifyWebhook() — intégrez-le dans n'importe quel projet.
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.payora.moneyUn appel API avec un ID de commande et un montant en fiat ou en crypto renvoie une URL de paiement hébergée.
Ils choisissent une pièce, scannent le QR ou ouvrent un portefeuille, et le paiement est confirmé en direct à la finalité.
Vérifiez la signature HMAC, créditez la commande une fois et regardez le paiement arriver sur votre solde.
Un fichier, aucune dépendance. createInvoice(), getInvoice() et verifyWebhook() — intégrez-le dans n'importe quel projet.
Les requêtes et les webhooks sont signés HMAC-SHA256 avec un décalage de timestamp et des clés d'idempotence.
JSON simple sur HTTPS — intégrez depuis n'importe quelle pile, pas seulement PHP.
<?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 retriesconst Payora = require('./payora');
const payora = new Payora('https://api.payora.money', process.env.PAYORA_KEY, process.env.PAYORA_SECRET);
// 1 — create an invoice and redirect
app.post('/checkout', async (req, res) => {
const inv = await payora.createInvoice({ order_id: 'ORDER-42', mode: 'fiat', amount: '9.99' }, 'ORDER-42');
res.redirect(inv.pay_url);
});
// 2 — webhook: verify over the RAW body
app.post('/payora/webhook', express.raw({ type: '*/*' }), (req, res) => {
const event = payora.verifyWebhook(req.body, req.headers);
if (event === null) return res.status(400).end();
if (event.status === 'paid') creditOrderOnce(event.id, event.order_id);
res.status(200).end();
});import os
from payora import Payora
payora = Payora('https://api.payora.money', os.environ['PAYORA_KEY'], os.environ['PAYORA_SECRET'])
# 1 — create an invoice and redirect
inv = payora.create_invoice({'order_id': 'ORDER-42', 'mode': 'fiat', 'amount': '9.99'}, 'ORDER-42')
return redirect(inv['pay_url'])
# 2 — webhook: verify over the RAW body
event = payora.verify_webhook(request.get_data(), dict(request.headers))
if event is None:
return ('', 400)
if event['status'] == 'paid':
credit_order_once(event['id'], event['order_id'])
return ('', 200)# signature = lowercase hex HMAC-SHA256(api_secret, timestamp + "." + raw_body)
BODY='{"order_id":"ORDER-42","mode":"fiat","amount":"9.99"}'
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"
# → 201 { "invoice_id": …, "status": "pending", "pay_url": "https://pay.payora.money/i/…", "expires": … }Obtenez votre clé API et votre secret en créant un compte. Le SDK complet est dans votre tableau de bord.
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ête | Valeur | Description |
|---|---|---|
X-Payora-Key | pk_… | Votre clé api_key publique. Identifie le magasin. |
X-Payora-Timestamp | unix seconds | Le moment où vous avez signé la demande, en secondes Unix. |
X-Payora-Signature | hex · 64 | HMAC-SHA256 hex en minuscules de timestamp + "." + corps brut, clé avec votre api_secret. |
X-Payora-Test | 1 | Marque 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-Key | string | Optionnel 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-Type | application/json | Requis sur les demandes qui contiennent un corps. |
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.
<?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);const crypto = require('crypto');
const body = JSON.stringify({ order_id: 'ORDER-42', mode: 'fiat', amount: '9.99' });
const ts = String(Math.floor(Date.now() / 1000));
const sig = crypto.createHmac('sha256', API_SECRET).update(ts + '.' + body).digest('hex');
const res = await fetch('https://api.payora.money/v1/invoice', {
method: 'POST',
headers: {
'X-Payora-Key': API_KEY,
'X-Payora-Timestamp': ts,
'X-Payora-Signature': sig,
'Idempotency-Key': 'ORDER-42',
'Content-Type': 'application/json',
},
body, // send exactly the bytes you signed
});import hashlib, hmac, json, time, urllib.request
body = json.dumps({'order_id': 'ORDER-42', 'mode': 'fiat', 'amount': '9.99'}, separators=(',', ':'))
ts = str(int(time.time()))
sig = hmac.new(API_SECRET.encode(), (ts + '.' + body).encode(), hashlib.sha256).hexdigest()
req = urllib.request.Request('https://api.payora.money/v1/invoice', data=body.encode(), method='POST', headers={
'X-Payora-Key': API_KEY,
'X-Payora-Timestamp': ts,
'X-Payora-Signature': sig,
'Idempotency-Key': 'ORDER-42',
'Content-Type': 'application/json',
})
invoice = json.load(urllib.request.urlopen(req))# GET has an empty body: the signed string is just the timestamp and a dot
TS=$(date +%s)
SIG=$(printf '%s.' "$TS" | openssl dgst -sha256 -hmac "$PAYORA_SECRET" | cut -d' ' -f2)
curl https://api.payora.money/v1/invoice/1042 \
-H "X-Payora-Key: $PAYORA_KEY" \
-H "X-Payora-Timestamp: $TS" \
-H "X-Payora-Signature: $SIG"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ètre | Type | Description |
|---|---|---|
order_id | string · required | Votre référence de commande unique (≤190 caractères). Une répétition est rejetée avec 409 — sécurisé contre les soumissions doubles. |
amount | string · required | Montant fiat (mode=fiat) ou montant crypto exact (mode=crypto). |
mode | fiat | crypto | Fiat par défaut : taux verrouillé par pièce au moment du paiement. La crypto fixe la pièce + le montant à l'avance. |
fiat_currency | string | Code fiat ISO pour le mode fiat (par défaut USD). |
currency | string | Monnaie pour le mode crypto (par exemple, TON, TRX, USDT_TRON). |
return_url | https URL | Où le bouton “Retour au magasin” du paiement renvoie le client — votre site. Absolument http(s) seulement. |
lang | en·ru·uk·es·de | Langue 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. |
ttl | seconds | Combien de temps la facture reste payable (120–86400 secondes, par défaut 1800). |
customer_email | Optionnel — reçu + envoyé par e-mail au payeur. | |
notes | string | Note 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.
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.
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.
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énement | status | Quand il se déclenche |
|---|---|---|
invoice.paid | paid | Le paiement est confirmé sur la chaîne. Contient le montant, la pièce et tx_hash. |
invoice.underpaid | underpaid | La facture a expiré après que moins que le montant attendu soit arrivé. |
invoice.expired | expired | La facture a expiré sans rien reçu. |
invoice.cancelled | cancelled | La 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.sent | sent | Un lot de paiements a été signé et diffusé. Contient chaque élément avec son tx_hash. |
| En-tête | Valeur | Description |
|---|---|---|
X-Payora-Id | uuid | Identifiant d'événement unique, le même que l'id dans le corps. Conservez-le pour ignorer les répétitions. |
X-Payora-Event | invoice.paid | Nom de l'événement. |
X-Payora-Timestamp | unix seconds | Quand cette tentative a été signée. |
X-Payora-Signature | hex · 64 | Même schéma que les requêtes : HMAC-SHA256 de l'horodatage + "." + corps brut avec votre api_secret. |
| Champ | Type | Description |
|---|---|---|
id | uuid | ID d'événement pour la dé-duplication. |
event | string | Nom de l'événement. |
invoice_id | int | Numéro de facture Payora. |
order_id | string | Votre référence de commande, telle qu'envoyée lors de la création de la facture. |
status | string | paid pour invoice.paid. |
currency | string | Monnaie utilisée par le payeur, par exemple USDT_TRON. |
amount | decimal string | Montant reçu. |
amount_units | integer string | Le même montant dans les plus petites unités de la monnaie — utilisez-le pour des comparaisons exactes. |
expected | decimal string | Montant demandé par la facture. |
fiat_amount | decimal string | null | Prix fiat de la facture tel que vous l'avez créée ; null pour les factures en mode crypto. |
fiat_currency | string | null | Code ISO de fiat_amount ; null pour les factures en mode crypto. |
tx_hash | string | Hash de transaction on-chain. |
paid_at | unix seconds | Quand l'événement a été créé. |
test | bool | true pour les factures sandbox. |
{
"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.
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.
hash_equals, crypto.timingSafeEqual, hmac.compare_digest.<?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// Express: capture the RAW body for this route
app.post('/payora/webhook', express.raw({ type: '*/*' }), (req, res) => {
const event = payora.verifyWebhook(req.body, req.headers); // HMAC + ±300 s, timingSafeEqual
if (event === null) return res.status(400).end();
if (event.event === 'invoice.paid' && !alreadyProcessed(event.id)) {
creditOrder(event.order_id, event.amount, event.currency, event.tx_hash);
rememberProcessed(event.id);
}
res.status(200).end(); // 2xx stops retries
});# Flask: request.get_data() is the exact raw body
@app.post('/payora/webhook')
def payora_webhook():
event = payora.verify_webhook(request.get_data(), dict(request.headers))
if event is None:
return ('', 400) # bad / forged / stale
if event['event'] == 'invoice.paid' and not already_processed(event['id']):
credit_order(event['order_id'], event['amount'], event['currency'], event['tx_hash'])
remember_processed(event['id'])
return ('', 200) # 2xx stops retries# Recompute the signature of a delivery you saved byte-for-byte to body.json
TS='1758038400' # X-Payora-Timestamp
SIG='…' # X-Payora-Signature
EXPECTED=$(printf '%s.' "$TS" | cat - body.json | openssl dgst -sha256 -hmac "$PAYORA_SECRET" | cut -d' ' -f2)
[ "$EXPECTED" = "$SIG" ] && echo valid || echo forgedEntrez 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é.
1758038400.{…}X-Payora-Timestamp: 1758038400
X-Payora-Signature: …Collez une signature à comparer
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.
# 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: …' …<?php
// The one-file PHP SDK covers invoices and webhooks; payouts are one signed POST.
$body = json_encode(['currency' => 'USDT_TRON', 'items' => [
['address' => 'TR7…', 'amount' => '250.00'],
['address' => 'TX9…', 'amount' => '99.50', 'tag' => 'batch-A'],
]], JSON_UNESCAPED_SLASHES);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . '.' . $body, $apiSecret);
$ch = curl_init('https://api.payora.money/v1/payout');
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: payroll-2026-01', 'Content-Type: application/json']]);
$batch = json_decode(curl_exec($ch), true); // 201: batch_id, status, totals, fee, itemsconst batch = await payora.createPayout({
currency: 'USDT_TRON',
items: [
{ address: 'TR7…', amount: '250.00' },
{ address: 'TX9…', amount: '99.50', tag: 'batch-A' },
],
}, 'payroll-2026-01'); // Idempotency-Key: a retried run never doubles
const status = await payora.getPayout(batch.batch_id);
// still pending? await payora.cancelPayout(batch.batch_id) releases the holdbatch = payora.create_payout({
'currency': 'USDT_TRON',
'items': [
{'address': 'TR7…', 'amount': '250.00'},
{'address': 'TX9…', 'amount': '99.50', 'tag': 'batch-A'},
],
}, 'payroll-2026-01') # Idempotency-Key: a retried run never doubles
status = payora.get_payout(batch['batch_id'])
# still pending? payora.cancel_payout(batch['batch_id']) releases the holdLa 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.
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 terminaison | Accès | Description |
|---|---|---|
GET/v1/health | no auth | Statut du service plus la liste des devises activées. |
POST/v1/invoice | auth | Cré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} | auth | Statut de la facture (propres factures uniquement) : status, remaining, et le charge — devise, adresse, montants attendus/reçus et tx_hash. |
POST/v1/payout | auth · 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/payout | auth | Listez vos lots de paiements récents (?limit=, par défaut 50). |
GET/v1/payout/{id} | auth | Statut du lot de paiements et éléments (propres lots uniquement). |
POST/v1/payout/{id}/cancel | auth | Annulez un lot encore en attente et libérez le solde retenu. Renvoie 409 si le lot n'est plus annulable. |
Aucun point de terminaison ne correspond.
Fichiers uniques sans dépendances. Chaque SDK signe les requêtes et vérifie les webhooks de la même manière.
PHP 7.4+ avec cURL, un fichier. createInvoice, getInvoice et verifyWebhook.
Node.js avec https et crypto intégrés uniquement. Factures, solde, paiements et verifyWebhook.
Bibliothèque standard Python uniquement. Factures, solde, paiements et verify_webhook.
Une collection Postman qui signe chaque appel pour vous.
La spécification lisible par machine de chaque point de terminaison, pour les générateurs de code et les clients API.
Un module prêt fait tout cela pour vous : facture, redirection et un webhook vérifié.
Réponses directes, y compris les inconfortables : garde, frais et que se passe-t-il quand quelque chose ne va pas.
Centre d'aideInstallez 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.
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.
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.
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.
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.
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.
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.
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.
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.