Ce que fait vraiment une API d'énergie TRON
Une API d'énergie TRON vend une seule chose, et ce n'est pas une remise sur des frais. Votre compte a besoin d'énergie pour exécuter le contrat USDT ; à défaut, le réseau prend des TRX à la place, à 100 sun l'unité. Une API d'énergie fait en sorte qu'un autre compte — un compte qui a gelé des TRX — prête son énergie, pour quelques minutes, à l'adresse qui signera votre transfert. Tout ce qui suit est la forme des requêtes autour de ce seul fait on-chain.
Sur la chaîne c'est une délégation, et vous n'en signez rien
Le compte prêteur signe une délégation qui nomme votre adresse. Votre adresse ne signe rien, n'approuve rien et n'accorde rien en retour : le réseau relève sa limite d'énergie, et l'événement s'arrête là (ce qu'est l'énergie). D'où le fait qu'une API d'énergie demande une adresse et jamais une clé — la seule signature de l'arrangement appartient à l'autre partie.
Le plus petit flux qui fonctionne
L'URL de base est https://api.nrg.market/v1 et la clé voyage dans un seul en-tête, Authorization: Bearer nrg_live_…. Elle n'est montrée qu'une fois, à sa création, et peut être restreinte à une liste d'adresses IP. Appelez-la depuis votre serveur : les endpoints authentifiés n'acceptent aucune origine de navigateur, parce qu'une clé qui atteint une page est une clé que tout le monde a. Il existe une seconde URL de base, sur un sous-domaine sandbox de nrg.market — la même surface /v1 sur de l'argent de test et une chaîne simulée, avec ses propres clés nrg_test_… et son propre espace client, documentée sur docs.nrg.market.
Commencez par POST /v1/estimate. Il ne réserve rien et ne débite rien, prend jusqu'à 500 destinataires en un appel, et renvoie ce qu'une commande calculerait.
curl -s https://api.nrg.market/v1/estimate \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"duration_s":300,
"transfers":[{"from":"TQ5NMqJjW8sBGqcpvUcXhbXm3jGnyDCmwK",
"to":"TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9"}]}'
{"items":[{"to":"TN3W…","kind":"single","energy_units":65000,"warnings":[]}],
"zone":"day","duration_s":300}
# abrégé — la réponse porte aussi price_trx par élément, total_trx et burn_cost_trx
kind vaut single pour un destinataire qui détient déjà des USDT, double pour un destinataire qui n'en détient pas et dont le compte de jeton doit d'abord être créé, et custom pour un contrat, tarifé à partir d'une exécution à blanc plutôt que de l'un des deux chiffres standards. from est facultatif et ne déplace aucun prix ; le donner achète deux réponses sur l'expéditeur — inactive_sender et blacklisted_sender parmi les warnings — avant qu'une commande, dans le mode que vous utilisez, ne puisse refuser sur l'une d'elles.
Puis la commande. Le mode a est celui où vous diffusez le transfert vous-même.
curl -s https://api.nrg.market/v1/orders \
-H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-H "Idempotency-Key: 8f3c1e02-6b47-4a1d-9d5c-0b2e7c4a1f90" \
-d '{"mode":"a","client_ref":"invoice-1042",
"transfers":[{"from":"TQ5NMqJjW8sBGqcpvUcXhbXm3jGnyDCmwK",
"to":"TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9"}]}'
La réponse est un 202 avec deux en-têtes qu'il vaut mieux lire que reconstituer : Location, l'URL propre de la commande, et Retry-After, les secondes à attendre avant la première interrogation puis entre deux interrogations. Le corps est la commande, normalement avec status à funded et send_before encore à null — l'argent est réservé et l'achat a commencé.
send_before apparaît quand l'énergie est confirmée sur la chaîne et que la commande atteint ready. C'est une fenêtre d'environ quatre minutes, comptée depuis la dernière délégation confirmée, si bien que tous les éléments d'un lot partagent une seule échéance ; lisez le champ plutôt que de supposer les quatre minutes. Guettez le champ, là encore, plutôt que le mot ready : une commande en mode A est honorée par la livraison de l'énergie et non par votre transfert, donc completed peut arriver avant que vous ayez envoyé quoi que ce soit.
Deux refus méritent d'être câblés avant la première commande réelle : 402 insufficient_balance, décidé avant que le moindre argent ne bouge et portant required_trx et available_trx, et 422 invalid_address avec details.reason à inactive_wallet — le portefeuille émetteur n'a jamais été activé, il n'y a donc aucun compte à qui déléguer (les échecs qu'il y a derrière).
La clé d'idempotence
POST /v1/orders exige une Idempotency-Key, et celle-ci est liée aux octets bruts du corps plutôt qu'au JSON analysé. Les mêmes octets renvoient la commande d'origine ; un autre corps sous la même clé donne un 409 idempotency_conflict et non une seconde commande ; une requête refusée par la validation ne consomme pas la clé. À l'échelle d'un lot, c'est ce qui transforme un délai réseau dépassé en une question qui a une réponse.
Ce que disent les en-têtes de limite de débit
Trois compteurs tournent par clé API : les commandes à 120 par minute, les requêtes de consultation à 600, et GET /v1/address-check à 60, parce que chaque échec de son cache est une question posée à la chaîne. Chaque réponse issue d'un compteur lié à une clé, les réponses réussies comprises, porte RateLimit-Limit, RateLimit-Remaining et RateLimit-Reset, de sorte qu'un client peut ralentir avant le refus plutôt qu'après ; passé la limite, c'est 429 rate_limited avec Retry-After. Un autre 429 veut dire à peu près l'inverse — too_many_auth_failures, où attendre ne sert à rien, parce que c'est l'identifiant lui-même qui est refusé. Branchez sur code, jamais sur message.
Webhooks, pour que la boucle ne soit pas une interrogation
Enregistrez un récepteur avec POST /v1/webhooks : l'url doit être en https, se résoudre vers un hôte public et ne porter aucun identifiant. Le secret de signature n'est rendu qu'une fois, à la création, et un compte ne garde pas plus de cinq points de réception actifs. Abonnez-vous à ce dont le flux a besoin — order.ready, order.completed, order.partially_completed, order.failed, plus les order.item.sent et order.item.expired par élément. Chaque livraison porte X-NRG-Timestamp, X-NRG-Event-Id et X-NRG-Signature, un HMAC-SHA256 sur l'horodatage, un point et le corps brut : vérifiez contre les octets que vous avez reçus plutôt que contre un JSON que vous auriez ré-encodé, et dédoublonnez sur event_id. POST /v1/webhooks/{webhook_id}/test envoie une vraie livraison signée sur le chemin réel et rapporte ce que votre point de réception a répondu, sans rien coûter.
Mode B : vous signez, nous diffusons
Le mode b remplace from et to par signed_tx, la transaction signée en hexadécimal, et nous la diffusons à l'instant où l'énergie se pose — personne ne reste à guetter une fenêtre de quatre minutes. Ce qui est accepté est étroit à dessein : un appel transfer du contrat USDT et rien d'autre, une seule signature du propriétaire, aucun TRX joint, et la multisignature refusée, parce que le jeu de clés d'une permission vit sur la chaîne et peut changer à notre insu. Il doit rester trois minutes de vie à la transaction quand la commande est créée, et sa propre expiration raccourcit la fenêtre — send_before ne dépasse jamais cette échéance moins une marge de diffusion. Faute de nous la remettre à temps, l'élément se ferme en failed avec broadcast_window_missed, réservation rendue en entier.
Mode C : de l'énergie sans destinataire nommé
Le mode c prend from et kind, et aucun destinataire — pour un portefeuille que vous voulez prêt avant que le lot existe. kind vaut single ou double, et c'est à vous de ne pas vous tromper : sans destinataire, il n'y a nulle part où lire le volume, donc un single là où il fallait double laisse le transfert à court, et la différence brûle des TRX. custom n'est délibérément pas proposé ici, puisqu'il résulte d'une exécution à blanc contre un destinataire-contrat précis. Les éléments portent to: null, n'atteignent jamais sent et passent à expired quand la fenêtre se ferme : le bail est arrivé à terme, ce qui est la fin normale et non un échec — et c'est débité, parce que l'énergie a été livrée.
Ce qui n'est jamais dans la requête
Il n'y a nulle part dans le contrat de champ pour une clé privée, dans aucun mode. Le mode A ne voit jamais votre transaction. Le mode B en voit une que vous avez déjà signée, et que nous ne pouvons pas modifier d'un octet sans casser cette signature ; elle est stockée chiffrée et effacée sept jours après que la commande est définitive. Le mode C n'a aucune transaction à voir. Ce qu'on donne à l'API, ce sont des adresses (le reste de ce que nous gardons et ne gardons pas).
Les parties qui ne demandent aucune clé
Les endpoints de consultation et le contrat ne demandent aucune clé, et leur débit est limité par adresse IP plutôt que par clé. GET /v1/tariff répond le prix d'une unité d'énergie en sun à l'instant, la tranche en cours, next_change_at et une grille horaire de référence — c'est ce que lit la page des tarifs à chaque chargement. GET /v1/market répond ce que les vendeurs que nous surveillons publient sur eux-mêmes, chaque chiffre horodaté de l'instant de sa lecture et notre propre prix classé parmi eux : c'est la page du marché. Citez l'endpoint plutôt qu'un chiffre : notre prix est recalculé toutes les quelques minutes.
Le contrat lui-même est à https://docs.nrg.market/openapi.yaml, et octet pour octet le même document à https://api.nrg.market/v1/contract.yaml — bon à savoir, parce que l'hôte de la documentation est derrière une couche de bordure qui refuse certains clients programmatiques avant que la requête ne nous parvienne. L'ETag y est le SHA-256 du corps, donc If-None-Match obtient un 304 quand rien n'a changé. Générez votre client depuis ce fichier : cette page est un résumé, et c'est au fichier que nous sommes tenus.