Développeurs
Une API de paiement crypto conçue pour le règlement direct
Créez une facture avec une seule requête authentifiée : Unheld renvoie l’adresse à payer, le montant exact et la profondeur de confirmation qu’il attendra. Les paiements arrivent directement sur un portefeuille que vous contrôlez — l’API ne prend jamais la garde de ce qu’elle rapporte.
Créer une facture
Un seul POST. Le montant s’écrit comme une personne l’écrit et il est mis à l’échelle côté serveur selon les décimales de l’actif : vous ne convertissez jamais à la main en unités de base.
curl -X POST https://api.unheld.io/api/v1/invoices \
-H "Authorization: Bearer $UNHELD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chainId": "11155111",
"assetType": "native",
"amountDecimal": "0.05",
"expiresInSeconds": 900,
"metadata": { "orderId": "A-1043" }
}'Réponse
{
"id": "e2b0…",
"status": "CREATED",
"receiveAddress": "0x…",
"expectedAmount": "50000000000000000",
"minConfirmations": 3,
"expiresAt": "2026-08-10T14:15:00.000Z",
"instructions": {
"chainId": "11155111",
"to": "0x…",
"amount": "50000000000000000",
"assetType": "native"
}
}receiveAddress est dérivée de votre portefeuille et verrouillée sur cette facture. expectedAmount est en unités de base. minConfirmations est le seuil propre à la chaîne, pas un réglage que nous avons inventé.
Authentification et portées
Les clés sont des jetons bearer, créées dans le tableau de bord et affichées une seule fois. Chaque clé porte une liste de portées explicite et une requête est rejetée si la clé n’a pas la portée requise pour cette route.
Portées disponibles
- invoices:write
- invoices:read
- webhooks:write
- webhooks:read
- balances:read
- customers:write
- customers:read
- subscriptions:write
- subscriptions:read
Accordez l’ensemble le plus étroit qui fonctionne. Une clé qui ne fait que créer des factures ne peut pas lire vos clients, et une clé de lecture divulguée ne peut rien déplacer — parce que rien dans cette API ne le peut.
Des webhooks vérifiables
Chaque livraison est signée. La signature est un HMAC-SHA256 calculé, à l’aide de votre secret de webhook, à partir de l’horodatage et du corps brut concaténés avec un point. Elle est envoyée sous forme de condensat hexadécimal.
Vérifier une livraison
const signature = crypto
.createHmac("sha256", webhookSecret)
.update(`${req.headers["x-timestamp"]}.${rawBody}`)
.digest("hex");
crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(req.headers["x-signature"])
);Comparez les empreintes en temps constant, rejetez un horodatage hors de votre fenêtre de tolérance, et traitez X-Request-Id comme clé d’idempotence : les tentatives répétées le réutilisent, donc recevoir deux fois le même événement est normal et ne doit pas être traité deux fois.
Événements de facture
Un paiement traverse des états plutôt que de passer d’impayé à payé, et chaque transition est un webhook. Le sous-paiement et le surpaiement sont des événements à part entière, pas des erreurs.
| Événement | Ce qui s’est passé |
|---|---|
| invoice.created | La facture existe et l’adresse de réception est surveillée. |
| invoice.receiving | Une transaction de paiement a été vue sur la chaîne mais n’est pas encore confirmée. |
| invoice.confirming | Le paiement se confirme et n’a pas atteint le seuil de la chaîne. |
| invoice.paid | Entièrement confirmé à la profondeur requise par la chaîne. Vous pouvez livrer. |
| invoice.underpaid | Moins que prévu est arrivé. Les paiements partiels s’additionnent, un second virement peut donc compléter. |
| invoice.overpaid | Plus que prévu est arrivé, enregistré exactement plutôt qu’arrondi. |
| invoice.expired | La fenêtre s’est fermée sans paiement complet. |
Testez tout le flux gratuitement
Testez factures, détection, confirmations et webhooks sans fonds réels. Les jetons de test n’ont aucune valeur monétaire. Une activité testnet n’est pas un paiement réel.
Périmètre
- Elle ne détient jamais de fonds. Il n’y a pas d’endpoint de solde d’où retirer, parce que les paiements arrivent sur votre adresse et y restent.
- Elle ne convertit ni ne règle en monnaie fiduciaire. Les paiements arrivent dans l’actif et sur la chaîne utilisés à l’envoi.
- Il n’existe pas encore de SDK officiels. Tout ici est du HTTP simple, et nous publions des exemples plutôt que des paquets que nous maintiendrions mal.
Questions des développeurs
Existe-t-il un bac à sable ?
Testez factures, détection, confirmations et webhooks sans fonds réels. Les jetons de test n’ont aucune valeur monétaire. Une activité testnet n’est pas un paiement réel.
Comment éviter de traiter deux fois le même webhook ?
Utilisez X-Request-Id comme clé d’idempotence. Les tentatives répétées réutilisent la même valeur : enregistrez-la et ignorez un doublon. Les répétitions sont attendues — une livraison qui échoue est retentée selon un calendrier plutôt qu’abandonnée.
Dois-je convertir moi-même les montants en unités de base ?
Non. Envoyez amountDecimal comme une personne l’écrirait et l’API le met à l’échelle selon les décimales de l’actif. La réponse renvoie expectedAmount en unités de base, si bien que les deux représentations sont explicites et ne peuvent pas diverger.
Exemples vérifiés sur l’API en direct le .
Développez d’abord sur testnet
Créez une clé, pointez-la vers une chaîne testnet et parcourez tout le flux avant que quoi que ce soit de réel ne bouge.
Commencer gratuitementTarifs · Ce que vous pouvez accepter aujourd’hui. · Votre argent ne transite pas par nous.