DOCUMENTATION
Développez avec SMetaGateway.
Tout ce qu’il faut pour créer des factures USDT TRC20 depuis votre serveur, envoyer les acheteurs vers la page de paiement et confirmer les paiements par webhooks signés.
Présentation
SMetaGateway est une couche de facturation non dépositaire pour l’USDT sur TRON. Les marchands enregistrent une adresse publique de réception ; les acheteurs la paient directement. La passerelle attribue à chaque facture un montant exact unique, suit son état, enregistre les données comptables et notifie votre serveur.
Tous les endpoints se trouvent sous /api/v1, sur la même origine que ce site. Les montants sont toujours des chaînes décimales d’au plus six décimales, jamais des nombres à virgule flottante.
- Votre serveur → SMetaGateway1POST /api/v1/invoices avec un Idempotency-Key
- SMetaGateway → Votre serveur2Facture avec payable_amount et checkout_url
- Votre serveur → Acheteur3Redirection de l’acheteur vers checkout_url
- Acheteur → SMetaGateway4L’acheteur ouvre la page de paiement et scanne le QR code
- Acheteur → Votre portefeuille TRON5L’acheteur envoie le montant USDT exact à votre adresse
- SMetaGateway6La passerelle trouve le montant exact sur la blockchain et confirme la facture
- SMetaGateway → Votre serveur7Webhook signé invoice.confirmed
- Votre serveur → SMetaGateway8GET /api/v1/invoices/{id} pour vérifier, puis honorer la commande
Flux de donnéesFlux d’argent
Démarrage rapide
1. Créez un espace et ajoutez une adresse de réception TRON. Copiez son identifiant de portefeuille.
2. Ouvrez Développeurs → Clés API et créez une clé avec une date d’expiration. Le secret commence par smg_ et n’est affiché qu’une seule fois : conservez-le en lieu sûr.
3. Créez une facture depuis votre serveur avec la requête ci-dessous. Enregistrez l’ID de la facture et le payable_amount exact.
4. Redirigez l’acheteur vers checkout_url. Ne marquez la commande comme payée qu’après un webhook invoice.confirmed vérifié et une consultation de la facture côté serveur.
curl -X POST "https://smg.sabco24.com/api/v1/invoices" \
-H "Authorization: Bearer $SMETA_API_KEY" \
-H "Idempotency-Key: order-1001" \
-H "Content-Type: application/json" \
-d '{"merchant_order_id":"1001","amount":"49.95","wallet_id":"WALLET_ID","description":"Example order","expires_in_minutes":20}'Authentification
Les intégrations serveur s’authentifient avec une clé API bearer : Authorization: Bearer smg_…. Les clés portent les portées invoices:read, invoices:write et ledger:read, et peuvent expirer après 30, 90 ou 365 jours. Une clé expirée renvoie 401 api_key_expired ; renouvelez-la dans le tableau de bord pour obtenir un nouveau secret. Gardez les clés sur votre serveur ; ne les intégrez jamais dans un navigateur ou une application mobile.
Le tableau de bord utilise un cookie de session HttpOnly. La gestion du compte, des portefeuilles, des clés API et des webhooks exige cette session propriétaire et n’est pas possible avec une clé API.
curl "https://smg.sabco24.com/api/v1/invoices/INVOICE_ID" \
-H "Authorization: Bearer $SMETA_API_KEY"Montants et identification
Envoyez le prix de base sous forme de chaîne décimale, par exemple "49.95". La passerelle ajoute un ajustement positif — de 0.000001 à 0.009999 USDT sous 100 USDT, ou de 0.000001 à 0.999999 USDT à partir de 100 USDT — et renvoie base_amount, adjustment et payable_amount séparément.
Le total exact est réservé 90 jours pour le même réseau, jeton et adresse de réception, tous marchands confondus. Les totaux inutilisés sont privilégiés ; un total réutilisé place la facture en review au lieu d’une confirmation automatique.
Réservé 90 jours par réseau, jeton et adresse de réception
{
"base_amount": "49.950000",
"adjustment": "0.003821",
"payable_amount": "49.953821"
}Factures et idempotence
POST /api/v1/invoices exige l’en-tête Idempotency-Key. Rejouer la même requête avec la même clé renvoie la facture d’origine avec idempotent_replay: true ; réutiliser la clé avec d’autres données renvoie 409 idempotency_conflict.
Chaque merchant_order_id n’a qu’une facture. Enregistrez l’ID de facture et le payable_amount avec votre commande et comparez-les à l’arrivée d’un webhook.
POST /invoices + Idempotency-Key- Nouvelle clé201 — nouvelle facture créée
- Même clé, même corpsFacture d’origine, idempotent_replay: true
- Même clé, corps différent409 idempotency_conflict
{
"invoice": {
"id": "6f1c…",
"merchant_order_id": "1001",
"base_amount": "49.950000",
"adjustment": "0.003821",
"payable_amount": "49.953821",
"status": "pending",
"mode": "live",
"checkout_url": "https://smg.sabco24.com/checkout/…",
"expires_at": "2026-10-21T12:20:00.000Z",
"reserved_until": "2027-01-19T12:00:00.000Z"
},
"idempotent_replay": false
}Page de paiement et statut
checkout_url est un lien d’accès : quiconque le possède voit les informations destinées au payeur, traitez-le donc comme confidentiel. La page affiche le nom du marchand, le détail du montant, l’adresse, le QR code et l’expiration, jamais vos métadonnées ni identifiants internes.
Le statut est pending, confirmed, expired ou review. La page expire après expires_in_minutes (20 par défaut, 1440 au maximum) ; la réservation du montant dure 90 jours indépendamment.
pending- Montant exact reçu
confirmed - Délai de paiement écoulé
expired - Montant réutilisé ou vérification manuelle requise
review
Webhooks signés
Enregistrez un endpoint HTTPS public (port 443) dans le tableau de bord. Son secret de signature n’est affiché qu’une fois. Événements : invoice.created, invoice.confirmed, invoice.expired, invoice.review et webhook.test. Les livraisons sont relancées jusqu’à huit fois et peuvent l’être manuellement.
Chaque requête porte les en-têtes X-SMeta-Event-Id, X-SMeta-Timestamp et X-SMeta-Signature. Calculez un HMAC-SHA256 sur timestamp + "." + corps brut, comparez en temps constant, rejetez les horodatages de plus de cinq minutes, puis analysez le JSON. Traitez chaque ID d’événement une seule fois.
- 1Lire le corps brut et les en-têtes X-SMeta-*
- 2Horodatage de moins de 5 minutes ?Rejeter (4xx)
- 3HMAC-SHA256(timestamp + "." + body)
- 4Comparaison à temps constant avec X-SMeta-SignatureRejeter (4xx)
- 5ID d’événement déjà traité ?Répondre 2xx, ignorer
- 6Mettre à jour la commande et répondre 2xx
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody: Buffer, headers: Record<string, string>, secret: string) {
const timestamp = headers['x-smeta-timestamp'];
const signature = headers['x-smeta-signature'] ?? '';
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return null;
const expected = 'sha256=' + createHmac('sha256', secret)
.update(timestamp + '.').update(rawBody).digest('hex');
const a = Buffer.from(expected), b = Buffer.from(signature);
if (a.length !== b.length || !timingSafeEqual(a, b)) return null;
const event = JSON.parse(rawBody.toString('utf8'));
return event.id === headers['x-smeta-event-id'] ? event : null;
}Erreurs et limites de débit
Les erreurs renvoient un JSON avec error.code et error.message. Statuts courants : 400 validation, 401 authentification, 403 portée ou origine, 404 introuvable, 409 conflit ou revue, 429 limite atteinte.
La création de factures est limitée à 120 requêtes par minute et par marchand. Relancez les réponses 429 et 5xx avec un délai progressif et la même Idempotency-Key.
{
"error": {
"code": "idempotency_conflict",
"message": "This idempotency key was used with different invoice details."
},
"mode": "live"
}Intégrations
Le tableau de bord propose 32 recettes prêtes à copier pour Node.js, NestJS, PHP, Laravel, Python, Django, Go, Java, C#, Ruby, React, Next.js, Vue et des plateformes e-commerce comme WooCommerce, Magento et Shopware. Le plugin WooCommerce téléchargeable est une préversion qui n’accepte pas encore les clés API de production.
Les recettes sont des exemples, pas des SDK publiés. Les exemples frontend appellent votre propre backend, qui détient la clé API.
Confirmation des paiements
La passerelle lit le réseau principal TRON via TronGrid pour trouver les transferts USDT TRC20 confirmés vers chaque adresse de réception ayant une facture ouverte, et revérifie chaque transfert à l’aide d’un reçu solidifié réussi. Un transfert du payable_amount exact entre la création et l’expiration de la facture la confirme, et le hash de la transaction est enregistré dans tx_hash.
Un transfert reçu après l’expiration, correspondant à un montant déjà utilisé ou visant une facture déjà en revue fait passer le statut à review et n’est jamais confirmé automatiquement. La détection prend généralement quelques minutes. L’absence de commission et une conception non dépositaire n’établissent pas à elles seules une exonération fiscale ou une autorisation réglementaire.