CryptoPayIn
Documentation développeur

Créez des paiements qui se règlent on-chain.

Tout ce qu'il faut pour créer un paiement, envoyer un client vers un paiement hébergé, suivre les confirmations et traiter les webhooks signés en production.

URL de base de l'APIVersion 1
https://cryptopayin.com/v1
ProtocoleREST / JSON
AuthentificationSecret Bearer
ModeProduction uniquement
Introduction

Une seule API, un seul parcours hébergé

CryptoPayIn établit le prix d'une commande dans la devise de présentation choisie, verrouille des instantanés vérifiés fiat/USD et crypto/USD, alloue une adresse de dépôt dédiée et surveille ses propres nœuds blockchain en attendant le paiement. La comptabilité interne, les frais et les soldes restent exprimés en USD. Votre backend reçoit immédiatement une URL de paiement, puis les évènements de cycle de vie signés.

URL de base/v1
Montants fiatUnités mineures ISO
Valeurs cryptoChaînes décimales
Expiration par défaut30 minutes
!

Ceci est une API en production. Il n'existe pas de préfixe bac à sable. Chaque création réussie alloue une véritable adresse on-chain. Utilisez un petit montant dans une devise prise en charge pour vos tests de bout en bout et conservez les clés secrètes sur votre serveur.

Comment s'articule l'intégration

1Créer une clé

Générez un secret une fois depuis Tableau de bord -> Développeurs.

2Créer un paiement

Envoyez en POST la devise de la commande, le montant et l'actif choisi.

3Ouvrir le paiement

Redirigez le client vers l'URL hébergée renvoyée.

4Traiter l'évènement

Vérifiez le HMAC et mettez à jour votre commande de façon idempotente.

Prise en main

Créez votre premier paiement

Générez une clé API dans le tableau de bord marchand, stockez le secret dans une variable d'environnement, puis créez un paiement depuis votre backend. L'exemple utilise l'ETH afin de pouvoir être testé sans avoir à choisir de réseau de token.

curl --request POST https://cryptopayin.com/v1/payments \
  --header "Authorization: Bearer $CPI_SECRET_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: order_1042" \
  --data '{
    "amount": 49.99,
    "currency": "USD",
    "asset": "ETH",
    "order_ref": "order_1042",
    "redirect_url": "https://shop.example/orders/1042/paid"
  }'

Exploitez la réponse

Conservez le id du paiement à côté de votre commande, puis redirigez le client vers checkout_url. Ne calculez jamais vous-même un montant en crypto ou une adresse de dépôt.

{
  "id": "P-9F27C1E4KD",
  "object": "payment",
  "status": "created",
  "amount": 49.99,
  "amount_decimal": "49.99",
  "amount_minor": 4999,
  "currency": "USD",
  "currency_minor_units": 2,
  "amount_usd": 49.99,
  "amount_usd_cents": 4999,
  "fx_rate_usd": "1.000000000000",
  "fx_source": "fixed:USD",
  "fx_observed_at": "2026-07-17T13:00:00+00:00",
  "fx_discrepancy_bps": 0,
  "asset": "ETH",
  "network": "mainnet",
  "crypto_amount": "0.01388612",
  "crypto_received": "0",
  "deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
  "exchange_rate": "3600.00000000",
  "exchange_rate_currency": "USD",
  "exchange_rate_source": "median:cb,cg,cl",
  "exchange_rate_source_count": 3,
  "exchange_rate_observed_at": "2026-07-17T13:00:00+00:00",
  "exchange_rate_discrepancy_bps": 12,
  "confirmations": 0,
  "confirmations_required": 12,
  "order_ref": "order_1042",
  "checkout_url": "https://cryptopayin.com/i/P-9F27C1E4KD",
  "expires_at": "2026-07-17T13:30:00+00:00",
  "created_at": "2026-07-17T13:00:00+00:00",
  "completed_at": null
}
Identifiants

Authentification

Chaque appel API utilise la clé secrète dans un en-tête HTTP Bearer. Les clés secrètes commencent par csk_live_. La valeur cpk_live_ associée est un identifiant public pour votre tableau de bord et ne doit jamais être utilisée comme identifiant Bearer.

AUTHAuthorization: Bearer csk_live_...Chaque endpoint
Affiché une seule fois

Le secret brut n'est renvoyé qu'à la création de la clé. CryptoPayIn stocke un hachage de mot de passe ainsi qu'un index de recherche SHA-256, jamais le secret en clair.

Clés indépendantes

Créez des clés distinctes par application ou environnement et révoquez-les indépendamment. Un compte peut détenir jusqu'à 50 clés actives.

Côté serveur uniquement

Ne placez jamais une valeur csk_live_ dans du JavaScript exécuté dans le navigateur, un binaire mobile, un dépôt public ou une page de paiement.

Portée des webhooks

Un endpoint de webhook peut couvrir tout le compte ou être rattaché à une seule clé API, ce qui garde les intégrations isolées.

i

Un secret manquant, malformé, révoqué ou inconnu renvoie 401 unauthorized. Un compte marchand suspendu ou fermé est rejeté de la même façon. Une clé valide utilisée en dehors de ses autorisations accordées renvoie 403 insufficient_scope.

Nouvelles tentatives sûres

Idempotence

Envoyez un Idempotency-Key unique à chaque création de paiement. Si votre connexion est interrompue après l'envoi, renvoyez le JSON identique avec la clé identique : CryptoPayIn renvoie le paiement d'origine au lieu d'allouer une nouvelle adresse.

CasRésultatHTTP
Première utilisationCrée et renvoie un nouveau paiement.201
Même clé + même JSONRenvoie le paiement existant avec Idempotent-Replayed: true.200
Même clé + JSON différentRejette la requête en tant que idempotency_conflict.409

Les clés sont propres aux identifiants API et peuvent contenir de 1 à 128 lettres, chiffres, points, tirets bas, deux-points ou tirets. Un UUID de commande durable constitue un bon choix. Le même mécanisme protège aussi les retraits, de sorte qu'un retrait renvoyé ne peut jamais déplacer les fonds deux fois.

API REST

Référence de l'API

L'API couvre les paiements, les liens de paiement, les boutiques, les produits, les soldes et les retraits. Les réponses utilisent du JSON UTF-8 sur HTTPS ; toute création ou mise à jour requiert Content-Type: application/json. Les mutations sont soumises aux autorisations de la clé appelante. Il n'existe volontairement aucun flux CORS pour navigateur : les appels doivent provenir de votre backend.

GET/v1/assetsDécouvrir les actifs disponibles
GET/v1/currenciesDécouvrir les devises de présentation fiat
POST/v1/paymentsCréer un paiement
GET/v1/paymentsLister et filtrer les paiements
GET/v1/payments/{id}Récupérer un paiement
i

La version 1 peut recevoir des champs et endpoints rétrocompatibles. Un changement de contrat non rétrocompatible utilisera un nouveau chemin de base plutôt que de modifier silencieusement /v1.

Référence de l'API

Lister les actifs

GET/v1/assetsAuthentification Bearer requise

Utilisez cet endpoint comme source de vérité pour les choix proposés au paiement. Il renvoie les entrées du catalogue activées, les taux actuels vérifiés de façon indépendante, les montants minimums en équivalent USD, ainsi que l'état de préparation du nœud et du flux de prix. Une entrée peut rester listée avec available: false tant qu'un nœud est en cours de synchronisation ou que son prix ne peut pas être vérifié.

curl https://cryptopayin.com/v1/assets \
  --header "Authorization: Bearer $CPI_SECRET_KEY"
{
  "object": "list",
  "data": [{
    "asset": "USDT",
    "network": "TRC20",
    "type": "token",
    "decimals": 6,
    "minimum_amount": 1,
    "currency": "USD",
    "base_confirmations": 19,
    "available": true,
    "rate_usd": "1.00000000",
    "rate_source": "median:cb,cg,cl",
    "rate_source_count": 3,
    "rate_discrepancy_bps": 4,
    "rate_status": "healthy",
    "rate_updated_at": "2026-07-17T13:00:00+00:00"
  }]
}

Catalogue et identifiants réseau

ActifValeur réseauAbréviationConfirmations de base
BTCmainnetBTC2
ETHmainnetETH6
USDTTRC20 / ERC20USDT.TRC2019 / 6
USDCERC20USDC.ERC206
DAIERC20DAI6
SHIBERC20SHIB6
PEPEERC20PEPE6
LTCmainnetLTC6
TRXmainnetTRX19
DOGEmainnetDOGE20
XMRmainnetXMR10
SOLmainnetSOL32
!

La disponibilité est dynamique. Ne codez pas en dur le tableau ci-dessus comme liste d'autorisation en direct. Pour les symboles multi-réseaux comme USDT, envoyez network explicitement ou utilisez l'abréviation ASSET.NETWORK.

Référence de l'API

Lister les devises fiat

GET/v1/currenciesAuthentification Bearer requise

Renvoie les devises de présentation activées, leur précision ISO et l'état actuel de la conversion USD. Ne proposez que les lignes avec available: true. L'USD est intrinsèque ; toute autre devise nécessite une cotation en direct récente et une vérification de référence indépendante. minimum_amount convertit dans cette devise le plancher le plus bas configuré parmi les actifs activés ; l'actif choisi peut exiger un montant plus élevé, pensez donc à toujours lire aussi GET /v1/assets.

curl https://cryptopayin.com/v1/currencies \
  --header "Authorization: Bearer $CPI_SECRET_KEY"
{
  "object": "list",
  "accounting_currency": "USD",
  "data": [{
    "currency": "EUR",
    "name": "Euro",
    "symbol": "€",
    "minor_units": 2,
    "available": true,
    "minimum_amount": "0.86",
    "rate_usd": "1.160000000000",
    "rate_source": "coinbase+ecb",
    "rate_source_count": 2,
    "rate_discrepancy_bps": 18,
    "rate_updated_at": "2026-07-17T13:00:00+00:00",
    "rate_reference_at": "2026-07-16T00:00:00+00:00"
  }]
}
i

Une devise omise sur POST /v1/payments signifie toujours USD par souci de rétrocompatibilité. Les devises sans décimale comme le JPY rejettent les montants fractionnaires. Traitez les minimums et taux du catalogue comme des données en direct, jamais comme des constantes codées en dur.

Référence de l'API

Créer un paiement

POST/v1/payments120 requêtes / minute / clé

Crée une facture dans la devise de présentation demandée, verrouille des instantanés fiat/USD et crypto/USD fraîchement vérifiés, calcule le montant exact en crypto et associe une adresse de dépôt on-chain dédiée.

Corps de la requête

ChampTypeExigenceDescription
amountnombre ou chaîne décimalerequisValeur en currency, à la précision ISO de cette devise. Son équivalent USD verrouillé ne doit pas dépasser $1,000,000.00 ; les minimums propres à l'actif s'appliquent également.
currencystringfacultatifDevise à 3 lettres activée, tirée de GET /v1/currencies. Par défaut : USD.
assetstringrequisSymbole tel que ETH, ou abréviation telle que USDT.TRC20.
networkstringconditionnelRequis lorsqu'un symbole existe sur plusieurs réseaux. Exemple : ERC20.
order_refstringfacultatifVotre identifiant de commande, 128 caractères maximum. Renvoyé dans les réponses API et les évènements.
customer_emailstringfacultatifAdresse e-mail valide, 190 caractères maximum. Stockée avec l'enregistrement de paiement du marchand.
redirect_urlstringfacultatifURL HTTPS, 255 caractères maximum, proposée après un paiement réussi.

Champs de la réponse

ChampTypeDescription
idstringIdentifiant de paiement stable commençant par P-.
statusstringÉtat actuel du cycle de vie.
amount / amount_decimal / amount_minornumber / string / integerValeur de présentation demandée sous forme pratique, décimale exacte et en unité mineure ISO.
currency / currency_minor_unitsstring / integerDevise de présentation verrouillée et sa précision.
amount_usd / amount_usd_centsnumber / integerValeur comptable interne en USD, immuable.
fx_rate_usd / fx_source / fx_observed_atdecimal string / string / ISO 8601Instantané verrouillé du taux USD par unité de présentation et ses métadonnées d'audit.
asset / networkstringActif on-chain résolu.
crypto_amountdecimal stringMontant exact que le client doit envoyer. Ne traitez jamais les décimales crypto comme des flottants binaires.
crypto_receiveddecimal stringTotal actuellement observé à l'adresse de dépôt.
deposit_addressstringAdresse dédiée allouée pour ce paiement.
exchange_ratedecimal stringTaux crypto/USD verrouillé utilisé pour calculer crypto_amount ; ce champ conserve sa signification d'origine de la v1.
exchange_rate_source / exchange_rate_observed_atstring / ISO 8601Instantané d'audit immuable du taux crypto.
confirmationsintegerNombre actuel de confirmations réseau.
confirmations_requiredintegerSeuil requis pour ce paiement. Les paliers USD plus élevés peuvent exiger des confirmations supplémentaires.
checkout_urlURLFacture hébergée à présenter au client.
expires_atISO 8601Date limite pour une facture impayée.
completed_atISO 8601 / nullHeure de règlement final une fois le paiement terminé.

Les deux conversions en direct sont vérifiées en termes de fraîcheur, de nombre de sources et de divergence avant la création. Si la vérification échoue, la création renvoie une erreur plutôt que d'utiliser un taux obsolète. Le montant en crypto est arrondi vers le haut à une précision utile pour l'actif, de sorte que l'arrondi ne pénalise jamais le marchand.

Référence de l'API

Lister les paiements

GET/v1/payments240 requêtes / minute / clé

Renvoie les paiements les plus récents en premier pour le compte marchand authentifié. Utilisez la pagination par curseur pour le rapprochement, et des filtres exacts pour retrouver une commande sans parcourir tout l'historique.

Paramètres de requête

ParamètreValeur par défautDescription
limit20Taille de page, de 1 à 100.
starting_afterID de paiement renvoyé comme next_cursor de la page précédente.
statusStatut exact du cycle de vie, tel que pending, completed ou expired.
order_refRéférence de commande marchande exacte, 128 caractères maximum.
curl "https://cryptopayin.com/v1/payments?status=completed&limit=20" \
  --header "Authorization: Bearer $CPI_SECRET_KEY"
{
  "object": "list",
  "data": [{
    "id": "P-9F27C1E4KD",
    "object": "payment",
    "status": "completed",
    "amount": 49.99,
    "currency": "USD",
    "asset": "ETH",
    "network": "mainnet",
    "crypto_amount": "0.01388612",
    "crypto_received": "0.01388612",
    "order_ref": "order_1042",
    "confirmations": 12,
    "confirmations_required": 12,
    "completed_at": "2026-07-17T13:12:42+00:00"
  }],
  "has_more": true,
  "next_cursor": "P-9F27C1E4KD"
}
i

Lorsque has_more vaut true, transmettez next_cursor sans le modifier en tant que starting_after. Les paramètres de requête inconnus ou répétés de type tableau sont rejetés plutôt qu'ignorés.

Référence de l'API

Récupérer un paiement

GET/v1/payments/{id}240 requêtes / minute / clé

Renvoie le même objet paiement qu'à la création, avec un statut actualisé, le montant reçu, le hash de transaction et les confirmations. Une clé ne peut récupérer que les paiements appartenant à son compte marchand.

curl https://cryptopayin.com/v1/payments/P-9F27C1E4KD \
  --header "Authorization: Bearer $CPI_SECRET_KEY"
i

Les webhooks doivent piloter les mises à jour normales des commandes. Utilisez la récupération pour rapprocher les données après un délai dépassé, vérifier un évènement, afficher une page de statut côté backend ou réparer des livraisons manquées.

Modèle d'états

Cycle de vie d'un paiement

Considérez toujours le statut renvoyé par l'API comme faisant foi. Ne déduisez jamais qu'un paiement est terminé à partir d'une redirection navigateur ou de l'affirmation du client selon laquelle il a payé.

created->pending->underpaidouconfirming->completed/overpaid
StatutSignificationAction du marchand
createdFacture et adresse allouées ; aucun financement détecté pour l'instant.Afficher le paiement hébergé.
pendingEn attente d'un paiement on-chain exploitable.Laisser la commande ouverte.
underpaidDes fonds sont arrivés en dessous de la tolérance du marchand.Demander au payeur d'envoyer le solde affiché.
confirmingValeur suffisante détectée ; en attente des confirmations.Ne pas encore livrer.
completedValeur requise et confirmations atteintes.Livrer une seule fois.
overpaidPlus que prévu a été confirmé.Livrer et examiner l'excédent.
expiredAucun paiement valable n'a été détecté avant l'expiration.Créer un nouveau paiement.
failedL'allocation de l'adresse ou le traitement a échoué.Consigner l'erreur et créer un nouveau paiement.
!

Les transferts on-chain sont irréversibles et CryptoPayIn ne dispose d'aucun mécanisme de remboursement — un paiement confirmé est définitif. Tout geste commercial éventuel se règle directement entre vous et votre client, en dehors de la plateforme.

Expérience client

Paiement hébergé

Chaque paiement créé via l'API inclut un checkout_url adapté à tous les écrans. Il affiche le marchand, le montant de présentation demandé, l'équivalent USD verrouillé le cas échéant, le montant exact en crypto, l'adresse de dépôt, le QR code, un avertissement réseau, un compte à rebours et la progression des confirmations en direct.

Taux verrouillé

Le client voit le même crypto_amount que celui renvoyé par l'API pendant la fenêtre de la facture.

Aucun compte client

Le payeur ne crée pas de compte CryptoPayIn et ne partage aucun identifiant.

Statut en direct

La page interroge le paiement en toute sécurité et passe de l'attente à la confirmation puis au paiement effectué.

Redirection marchand

Une redirect_url HTTPS est proposée après le succès ; elle ne constitue pas une preuve de paiement.

i

Conservez la livraison côté backend. La navigation dans le navigateur peut être abandonnée, répétée ou falsifiée ; seul un webhook vérifié ou un GET authentifié prouve l'état réel du paiement.

Identifiants

Autorisations & scopes

Chaque clé API porte un ensemble fixe d'autorisations choisies lors de sa création dans Tableau de bord → Développeurs. Chaque endpoint vérifie les scopes de la clé avant toute action ; un appel en dehors du périmètre accordé renvoie 403 insufficient_scope avec un en-tête X-Required-Scope indiquant l'autorisation manquante. Les scopes sont définis une fois pour toutes à la création et ne peuvent pas être élargis ensuite — générez plutôt une nouvelle clé. Les clés créées avant l'existence des scopes conservent exactement leur capacité d'origine : payments:read et payments:write.

ScopeAccordeEndpoints
payments:readLister et récupérer les paiementsGET /v1/payments, GET /v1/payments/{id}
payments:writeCréer des paiements hébergésPOST /v1/payments
links:readLister et récupérer les liens de paiementGET /v1/links, GET /v1/links/{id}
links:writeCréer, modifier, mettre en pause et supprimer des liens de paiementPOST/PATCH/DELETE /v1/links
shops:readLister et récupérer les boutiques et leurs produitsGET /v1/shops, GET .../products
shops:writeCréer et modifier des boutiques, produits et variantesPOST/PATCH/DELETE /v1/shops et produits
balance:readLire les soldes crypto et les estimations en USDGET /v1/balance
payouts:readLister et récupérer les retraitsGET /v1/payouts, GET /v1/payouts/{id}
payouts:writeDemander des retraits on-chainPOST /v1/payouts
!

payouts:write déplace des fonds on-chain et est irréversible. Accordez-le uniquement aux clés en qui vous avez pleinement confiance, conservez ces clés côté serveur, et préférez une clé dédiée par processus automatisé. GET /v1/account indique les scopes de la clé appelante ainsi que les limites de votre compte.

Acheteurs machines

Paiement par agent

Chaque lien de paiement actif est aussi un paiement lisible par une machine : un agent IA ou n'importe quel script peut le découvrir, créer une facture et lire la livraison sans navigateur — et sans aucune clé API, car il s'agit d'endpoints acheteurs publics sur le domaine du lien, pas d'endpoints marchand. Contrat complet et exemple concret : cryptopayin.com/agents.

GEThttps://cryptopaylink.co/pay/{link}.jsonpublic · découverte

Renvoie l'état, la tarification, les actifs acceptés et le contrat exact des données d'entrée pour l'appel de facturation (champs requis, schéma de livraison, variantes).

POSThttps://cryptopaylink.co/pay/{link}/invoicepublic · prend en charge Idempotency-Key

Crée la facture en passant par le même cœur applicatif, le même instantané de tarification et les mêmes limites anti-abus que la page hébergée, et renvoie l'adresse de dépôt, le montant exact en crypto, un URI de portefeuille et l'URL du reçu. L'agent règle ensuite on-chain depuis n'importe quel portefeuille qu'il contrôle.

GEThttps://cryptopaylink.co/pay/{link}/receipt?p={payment}public · interrogation toutes les 5–10 s

Statut et confirmations en direct ; une fois le paiement terminé, la réponse porte la livraison — votre contenu texte, une URL privée ou une clé de licence réservée à ce paiement — ainsi que votre message de succès et votre URL de redirection.

Les boutiques parlent le même protocole

Les vitrines exposent le même parcours sur leur propre domaine : le catalogue avec le stock en direct, puis un unique appel qui valide le panier, réserve le stock et renvoie la facture.

GEThttps://shopycrypto.com/s/{shop}.jsonpublic · catalogue
POSThttps://shopycrypto.com/s/{shop}/orderpublic · panier → facture, prend en charge Idempotency-Key
GEThttps://shopycrypto.com/s/{shop}/o/{order}/receipt?p={payment}public · interrogation toutes les 5–10 s

Contrôles vendeur

Le paiement par agent est activé par défaut et coûte la même commission fixe de 1 %. Désactivez-le pour tout le compte dans Tableau de bord → Paramètres → Général → IA & paiement par agent : les endpoints machine des liens et boutiques répondent alors 403 agents_disabled tandis que vos pages de paiement pour humains continuent de fonctionner. Les paiements créés par des agents ne portent aucun indicateur particulier — ce sont des paiements ordinaires dans votre tableau de bord, vos webhooks et vos exports.

Ressources marchand

Boutiques

Une vitrine hébergée qui regroupe des produits sous une seule page à votre marque. Un compte détient jusqu'à 10 boutiques. Les produits sont gérés via les endpoints produits imbriqués ci-dessous.

GET/v1/shopsshops:read
POST/v1/shopsshops:write
GET/v1/shops/{id}shops:read
PATCH/v1/shops/{id}shops:write
DELETE/v1/shops/{id}shops:write

Corps de la requête

ChampTypeExigenceDescription
namestringrequis2–80 caractères.
taglinestringfacultatifJusqu'à 160 caractères.
themestringfacultatiflight (par défaut) ou dark.
accentstringfacultatifCouleur d'accent hexadécimale tirée de la palette de la boutique, renvoyée en tant que accent_palette sur GET /v1/shops.
accepted_assetsarray of stringsfacultatifActifs par défaut pour les produits de la boutique, par ex. ["BTC","LTC","XMR"]. Appliqué à tous les produits en cas de modification.
statusstringfacultatifPATCH uniquement : active ou paused.
i

Une boutique désactivée par CryptoPayIn pour des raisons de conformité aux règles ne peut être ni réactivée ni supprimée via l'API, et renvoie admin_disabled (403). La suppression d'une boutique retire ses produits ; les paiements passés restent intacts.

Ressources marchand

Produits & variantes

Les produits vivent au sein d'une boutique. Chaque boutique détient jusqu'à 50 produits. Un produit peut être numérique (avec livraison instantanée) ou physique (avec pays de livraison), et peut exposer jusqu'à 30 combinaisons de variantes construites à partir de 1–3 groupes d'options.

GET/v1/shops/{shop}/productsshops:read
POST/v1/shops/{shop}/productsshops:write
GET/v1/shops/{shop}/products/{id}shops:read
PATCH/v1/shops/{shop}/products/{id}shops:write
DELETE/v1/shops/{shop}/products/{id}shops:write

Corps de la requête

ChampTypeExigenceDescription
titlestringrequis3–120 caractères.
description / blurbstringfacultatifDescription complète et une ligne de fiche produit de ≤200 caractères.
emojistringfacultatifUn seul emoji affiché sur la fiche produit.
featuredbooleanfacultatifAu plus un produit mis en avant par boutique.
product_typestringfacultatifdigital (par défaut) ou physical.
shipping_countriesarray of stringsconditionnelPhysique uniquement : codes ISO tels que ["FR","BE"], ou ["*"] pour le monde entier.
amount_type / currency / amount / min / maxmixedconditionnelTarification de base, règles identiques aux liens de paiement. Les produits physiques doivent être fixed.
max_usesintegerfacultatifPlafond total de ventes (0 = illimité).
delivery_type + delivery_text/url/keysmixedfacultatifLivraison numérique pour le produit de base, mêmes formats que pour les liens de paiement.
variant_optionsarrayfacultatif1–3 groupes {name, values[]}, chacun avec 2–10 valeurs. Les combinaisons ne doivent pas dépasser 30.
variantsarrayconditionnelUn objet par combinaison (voir ci-dessous). Requis et exhaustif lorsque variant_options est présent.
statusstringfacultatifPATCH uniquement : active ou paused.

Objet variante

ChampTypeDescription
optionsarray of stringsUne valeur par groupe d'options, dans l'ordre des groupes, par ex. ["Pro","Lifetime"].
pricenumber or stringPrix de la variante dans la devise du produit.
stockinteger or nullUnités restantes, ou null pour illimité.
delivery_type + delivery_text/url/keysmixedSubstitution facultative de la livraison numérique par variante (inherit par défaut). Les clés doivent être uniques sur l'ensemble du produit.
curl -X POST https://cryptopayin.com/v1/shops/SH-JYRK8TFJ/products \
  -H "Authorization: Bearer $CPI_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Software license",
    "amount": 30,
    "currency": "USD",
    "variant_options": [
      {"name": "Edition", "values": ["Standard", "Pro"]},
      {"name": "Term", "values": ["1 year", "Lifetime"]}
    ],
    "variants": [
      {"options": ["Standard","1 year"], "price": 30, "delivery_type": "keys", "delivery_keys": ["S1Y-1"]},
      {"options": ["Standard","Lifetime"], "price": 79, "stock": 10, "delivery_type": "keys", "delivery_keys": ["SLT-1"]},
      {"options": ["Pro","1 year"], "price": 59, "delivery_type": "keys", "delivery_keys": ["P1Y-1"]},
      {"options": ["Pro","Lifetime"], "price": 149, "stock": 5, "delivery_type": "keys", "delivery_keys": ["PLT-1"]}
    ]
  }'
i

PATCH préserve les commandes existantes et les clés déjà livrées. Pour ajuster les prix ou le stock, renvoyez le tableau variants correspondant ; les combinaisons omises sont mises en pause si elles ont des commandes, sinon supprimées. Un produit peut détenir au maximum 10,000 clés de licence actives sur l'ensemble de sa base et de ses variantes, et chaque clé doit être unique au sein du produit.

Ressources marchand

Solde

GET/v1/balancebalance:read

Renvoie vos soldes crypto réglés par actif, avec une estimation USD de meilleur effort et les frais réseau facturés lors d'un retrait. La comptabilité interne est toujours en USD ; les soldes s'accumulent à partir des paiements terminés, nets de la commission marchand.

{
  "object": "list",
  "accounting_currency": "USD",
  "minimum_payout_usd": 25,
  "data": [{
    "asset": "USDT",
    "network": "TRC20",
    "amount": "99.099",
    "usd_estimate": 99.02,
    "payout_network_fee": "2.445463"
  }]
}
i

usd_estimate vaut null lorsqu'un taux en direct vérifié est momentanément indisponible ; le solde sous-jacent reste exact. Utilisez ces valeurs pour décider des retraits, pas pour la comptabilité finale.

Ressources marchand

Retraits

Transférez de la crypto réglée vers un portefeuille externe. Les retraits étant irréversibles, cet endpoint applique toutes les mêmes garanties que le tableau de bord : une destination valide pour l'actif, un taux en direct vérifié, le minimum du compte, un solde suffisant incluant les frais réseau, et une confirmation à deux facteurs lorsque la 2FA est activée sur votre compte.

GET/v1/payoutspayouts:read
POST/v1/payoutspayouts:write · 30 / min / clé
GET/v1/payouts/{id}payouts:read

Corps de la requête

ChampTypeExigenceDescription
assetstringrequisSymbole ou abréviation, par ex. LTC ou USDT.TRC20.
networkstringconditionnelRequis lorsque le symbole existe sur plusieurs réseaux.
amountnumber or stringrequisMontant à envoyer, hors frais réseau, à la précision de l'actif. Sa valeur en USD doit atteindre le minimum du compte.
addressstringrequisAdresse de destination, validée pour la blockchain de l'actif.
notestringfacultatifVotre propre référence, jusqu'à 255 caractères.
totp_codestringconditionnelCode actuel à 6 chiffres ou code de récupération. Requis lorsque la 2FA est activée sur le compte.
curl -X POST https://cryptopayin.com/v1/payouts \
  -H "Authorization: Bearer $CPI_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: withdraw-2026-07-19-01" \
  -d '{
    "asset": "USDT.TRC20",
    "amount": "50",
    "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "note": "weekly settlement"
  }'
{
  "id": "W-EM64ZCJB",
  "object": "payout",
  "status": "requested",
  "asset": "USDT",
  "network": "TRC20",
  "amount": "50",
  "fee": "2.445463",
  "total_debited": "52.445463",
  "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "txid": null,
  "confirmations": 0,
  "created_at": "2026-07-19T19:10:00+00:00"
}

Cycle de vie du statut

StatutSignification
requestedRéservé sur votre solde ; en attente d'examen par un opérateur ou d'approbation automatique.
approved / processingValidé et mis en file d'attente pour diffusion par l'exécuteur.
sentDiffusé on-chain ; txid est renseigné.
confirmedA atteint les confirmations requises. Définitif.
failedN'a pas pu être envoyé ; failure_message en explique la raison et le solde est restitué.
cancelledAnnulé avant diffusion ; le solde réservé est restitué.

Envoyez un Idempotency-Key afin qu'une nouvelle tentative réseau ne puisse jamais créer un second retrait : la même clé avec le même corps renvoie le retrait d'origine (Idempotent-Replayed: true) ; la même clé avec un corps différent renvoie 409 idempotency_conflict. Le code 2FA est volontairement exclu de l'empreinte d'idempotence, afin qu'un code qui change ne déclenche pas un faux conflit. La réservation débite immédiatement votre solde ; un retrait échoué ou annulé le restitue.

Ressources marchand

Compte

GET/v1/accounttoute clé valide

Renvoie le profil de votre compte, les scopes de la clé appelante, votre commission de plateforme et toutes les limites en vigueur — utile pour une intégration auto-configurable ou une vérification préalable.

{
  "object": "account",
  "id": "MC67T3PHQZ",
  "fee_bps": 100,
  "fee_percent": 1,
  "default_currency": "USD",
  "two_factor_enabled": false,
  "api_key": {"label": "production", "scopes": ["payments:read","payments:write"]},
  "limits": {
    "shops": {"used": 1, "max": 10},
    "payment_links": {"used": 0, "max": 50},
    "products_per_shop_max": 50,
    "variant_combinations_per_product_max": 30,
    "license_keys_per_product_max": 10000,
    "active_api_keys_max": 50,
    "checkout_fields_per_link_max": 5
  },
  "minimum_payout_usd": 25
}
Évènements serveur à serveur

Webhooks

Ajoutez jusqu'à 10 endpoints HTTPS publics dans Tableau de bord -> Développeurs. Chaque endpoint reçoit son propre secret de signature whsec_..., affiché une seule fois. Il peut écouter tout le compte ou être rattaché à une clé API active spécifique ; les endpoints rattachés à une clé ne reçoivent que les paiements créés avec cette clé.

Vérifiez avant de traiter

CryptoPayIn signe le corps brut exact de la requête à l'aide du secret de l'endpoint. La version 1 signe timestamp + "." + raw_body. Rejetez les horodatages obsolètes avant d'accepter l'évènement.

import crypto from "node:crypto";

const timestamp = req.headers["x-cpi-timestamp"];
const signature = req.headers["x-cpi-signature"];
const rawBody = req.rawBody; // Buffer captured before JSON parsing

if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
  throw new Error("stale webhook");
}
const expected = "sha256=" + crypto
  .createHmac("sha256", process.env.CPI_WEBHOOK_SECRET)
  .update(Buffer.concat([Buffer.from(`${timestamp}.`), rawBody]))
  .digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) throw new Error("invalid webhook signature");

En-têtes de livraison

En-têteExempleObjet
Content-Typeapplication/jsonCorps JSON UTF-8.
X-CPI-Timestamp1784293200Secondes Unix incluses dans le message signé.
X-CPI-Signaturesha256=...HMAC-SHA256 en hexadécimal.
X-CPI-Signature-Versionv1Version du schéma de signature.
X-CPI-Event-Idevt_a12b...ID logique stable de l'évènement ; identique à chaque nouvelle tentative.
X-CPI-Delivery-Id1842ID stable de l'enregistrement de livraison de l'endpoint.

Charge utile du paiement

{
  "event_id": "evt_a12b34c56d78e90f12345678",
  "event": "payment.completed",
  "id": "P-9F27C1E4KD",
  "status": "completed",
  "order_ref": "order_1042",
  "amount": 49.99,
  "amount_decimal": "49.99",
  "amount_minor": 4999,
  "currency_minor_units": 2,
  "currency": "USD",
  "amount_usd": 49.99,
  "amount_usd_cents": 4999,
  "fx_rate_usd": "1.000000000000",
  "fx_source": "fixed:USD",
  "fx_observed_at": "2026-07-17T13:00:00Z",
  "fx_discrepancy_bps": 0,
  "exchange_rate": "3600.00000000",
  "exchange_rate_currency": "USD",
  "exchange_rate_source": "median:cb,cg,cl",
  "exchange_rate_source_count": 3,
  "exchange_rate_observed_at": "2026-07-17T13:00:00Z",
  "exchange_rate_discrepancy_bps": 12,
  "asset": "ETH",
  "network": "mainnet",
  "crypto_amount": "0.01388612",
  "crypto_received": "0.01388612",
  "txid": "0x9d81...75af",
  "confirmations": 12,
  "confirmations_required": 12,
  "deposit_address": "0x71b8c3d4700000000000000000000000000084e2",
  "sent_at": "2026-07-17T13:12:42Z"
}

Nouvelles tentatives et sécurité de l'endpoint

Renvoyez n'importe quel code 2xx

Une livraison réussit avec un code HTTP 200-299. Effectuez les traitements coûteux de façon asynchrone et répondez rapidement.

Six tentatives au total

Le corps exact et l'ID de l'évènement sont conservés ; en cas d'échec, une nouvelle tentative a lieu après environ 1 minute, 5 minutes, 30 minutes, 2 heures puis 6 heures.

Aucune redirection

Les réponses 3xx ne sont pas suivies. Enregistrez directement l'URL HTTPS finale.

Destinations publiques uniquement

Les IP privées, de boucle locale, link-local et réservées sont bloquées ; chaque réponse DNS est validée et la connexion est épinglée.

!

Les livraisons se font au moins une fois. Rendez votre gestionnaire idempotent en enregistrant event_id avec une contrainte d'unicité avant la livraison. Récupérez l'objet via l'API lors du rapprochement d'un évènement inattendu.

Webhooks

Référence des évènements

payment.completedValeur attendue confirmée.
payment.overpaidPlus que prévu confirmé.
payment.underpaidFinancement inférieur à la tolérance détecté.
payment.expiredFenêtre de facture impayée fermée.
payment.failedÉchec de la configuration ou du traitement du paiement.
payout.sentRetrait diffusé on-chain.
payout.confirmedRetrait ayant atteint les confirmations.
payout.failedLe retrait n'a pas pu aboutir.
webhook.testTest de connectivité manuel.

Structure de l'évènement de retrait

{
  "event_id": "evt_b98c76d54e32a10f87654321",
  "event": "payout.sent",
  "id": "W-8J2K7M4RQP",
  "status": "sent",
  "asset": "ETH",
  "network": "mainnet",
  "amount": "0.25",
  "fee": "0.00081768",
  "address": "0x84f2...9bc1",
  "txid": "0xa1c4...07ee",
  "confirmations": 0,
  "note": "weekly treasury",
  "sent_at": "2026-07-17T14:08:31Z"
}
Fiabilité

Erreurs et limites de débit

Les erreurs utilisent toujours une seule enveloppe JSON. Basez votre logique sur error.type ; le message destiné aux humains peut être amélioré sans changement de version. Citez error.request_id ou l'en-tête de réponse X-Request-Id correspondant lorsque vous contactez le support.

{
  "error": {
    "type": "ambiguous_asset",
    "message": "specify network (e.g. USDT.ERC20 or USDT.TRC20)",
    "request_id": "b942e21f8dca4b06b8672eb9"
  }
}
HTTPTypes courantsSignification
400invalid_request, unknown_parameterJSON, requête ou en-tête d'idempotence malformé.
401unauthorizedIdentifiant ou compte manquant, invalide ou inactif.
403insufficient_scope, admin_disabledClé valide mais dépourvue de l'autorisation requise (voir X-Required-Scope), ou ressource verrouillée par un administrateur.
404not_foundEndpoint inconnu, ou ressource en dehors de ce compte marchand.
405method_not_allowedUtilisez la méthode indiquée dans l'en-tête Allow.
409idempotency_conflictClé réutilisée avec un JSON différent.
413request_too_largeLe corps JSON dépasse 64 Kio.
415unsupported_media_typeLe corps du POST n'est pas déclaré comme application/json.
422invalid, limit, invalid_amount, below_minimum, bad_address, 2fa_required, unsupported_assetRequête bien formée ayant échoué à une validation déterministe ou atteint un plafond de ressource.
429rate_limitedPatientez jusqu'à Retry-After.
500server_errorÉchec inattendu ; nouvelle tentative possible en toute sécurité avec la même clé d'idempotence.
503maintenance, temporarily_unavailable, asset_unavailable, no_rate, price_stale, fiat_rate_unavailable, fiat_rate_stale, derive_failedÉchec transitoire de la plateforme, d'un nœud, d'un prix ou de l'allocation d'adresse. Aucune conversion obsolète n'est substituée.

Limites actuelles

PortéeLimiteFenêtre
Plafond de sécurité Nginx par IP10 requêtes/seconde, rafale de 30Continu
Plafond IP non authentifiée300 requêtes60 secondes
POST /v1/payments, links, shops, products120 requêtes par clé API60 secondes
POST /v1/payouts30 requêtes par clé API60 secondes
Endpoints GET240 requêtes par clé API60 secondes

Limites de compte

RessourcePlafond
Boutiques par compte10
Liens de paiement par compte50
Produits par boutique50
Combinaisons de variantes par produit30
Clés de licence par produit / lien10,000
Questions de paiement par lien5
Clés API actives par compte50

Consultez votre utilisation en direct par rapport à ces plafonds depuis GET /v1/account.

Les réponses réussies limitées au niveau applicatif exposent X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset. Effectuez de nouvelles tentatives pour 429, 500 et 503 avec un backoff exponentiel et du jitter. Pour un POST, réutilisez toujours le Idempotency-Key d'origine et un JSON identique.

Sécurité en production

Sécurité de l'intégration

Conservez les secrets API dans un gestionnaire de secrets

Chargez-les à l'exécution ; ne journalisez jamais la valeur complète et ne la validez jamais dans le contrôle de code source.

Appelez l'API depuis votre backend

Un client navigateur ou mobile ne peut pas conserver en toute sécurité un secret marchand.

Vérifiez le corps brut du webhook

Vérifiez la fraîcheur de l'horodatage et utilisez une comparaison de signature en temps constant avant l'analyse du JSON.

Rendez la livraison idempotente

Enregistrez les évènements/commandes traités de façon transactionnelle afin qu'une nouvelle tentative ne livre jamais deux fois.

Faites confiance à l'état final de l'API, pas aux redirections

Récupérez le paiement lorsqu'un évènement est inattendu ou que votre état local diverge.

Effectuez une rotation par chevauchement

Créez une clé de remplacement, déployez-la, vérifiez le trafic, puis supprimez l'ancienne clé.

!

L'accès au compte est contrôlé par une clé marchand à 16 chiffres non récupérable, éventuellement protégée par TOTP. Conservez à la fois l'accès marchand et les secrets API avec le même soin que des identifiants de portefeuille.

Lancement

Check-list de mise en production

1
Créez une clé API de production dédiée

Ne réutilisez pas la copie personnelle d'un développeur sur plusieurs services.

2
Interrogez les deux catalogues en direct

Utilisez GET /v1/assets et GET /v1/currencies ; n'affichez que les entrées présentes et available: true.

3
Ajoutez et testez votre endpoint de webhook

Enregistrez le secret de signature une seule fois ; vérifiez l'horodatage et la signature, puis dédupliquez l'ID d'évènement stable.

4
Utilisez une clé d'idempotence pour chaque commande

Testez une nouvelle tentative en double et vérifiez qu'un seul ID de paiement existe.

5
Testez les pannes de taux, les sous-paiements et les expirations

L'état de votre commande doit rester sûr face à des taux fiat obsolètes, des actifs indisponibles, des confirmations retardées et tous les chemins non nominaux.

6
Effectuez un rapprochement quotidien

Comparez vos commandes avec les états de paiement de l'API, les journaux de webhooks et le grand livre marchand.

Prêt à intégrer ?

Créez un compte en quelques secondes, générez une clé et gardez cette référence à portée de main pendant que vous codez.

Créer un compte