Qué hace en realidad una API de energía TRON
Una API de energía TRON vende una sola cosa, y no es un descuento sobre una comisión. Su cuenta necesita energía para ejecutar el contrato de USDT, y sin ella la red se cobra en TRX, a 100 sun por cada unidad. Una API de energía consigue que otra cuenta —una que tiene TRX en staking— preste su energía durante unos minutos a la dirección que firmará su transferencia. Todo lo que sigue es la forma de las peticiones alrededor de ese único hecho on-chain.
En la cadena es una delegación, y usted no firma nada de ella
La cuenta que presta firma una delegación que nombra su dirección. Su dirección no firma nada, no aprueba nada y no concede nada a cambio: la red sube su límite de energía, y en eso consiste todo el evento (qué es la energía). Por eso una API de energía pide una dirección y nunca una clave: la única firma del acuerdo es la del otro lado.
El flujo mínimo que funciona
La URL base es https://api.nrg.market/v1 y la clave viaja en una sola cabecera, Authorization: Bearer nrg_live_…. Se muestra una vez al emitirla y puede fijarse a una lista de IP. Llámela desde su servidor: los endpoints autenticados no admiten ningún origen de navegador, porque una clave que llega a una página es una clave que tiene todo el mundo. Hay una segunda URL base, en un subdominio sandbox de nrg.market: la misma superficie /v1 sobre dinero de prueba y una red simulada, con sus propias claves nrg_test_… y su propio panel, y está documentada en docs.nrg.market.
Empiece por POST /v1/estimate. No reserva nada ni cobra nada, admite hasta 500 destinatarios en una llamada y devuelve lo que calcularía un pedido.
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}
# recortado: la respuesta trae además price_trx por ítem, total_trx y burn_cost_trx
kind es single cuando el destinatario ya tiene USDT, double cuando no lo tiene y antes hay que crearle una cuenta de token, y custom cuando es un contrato, cuyo precio sale de una simulación y no de ninguna de las dos cifras estándar. from es opcional y no mueve el precio; indicarlo compra dos respuestas sobre el remitente — inactive_sender y blacklisted_sender entre los warnings — antes de que un pedido en el modo que usted use pueda rechazarlo por una de ellas.
Después, el pedido. El mode a es aquel en el que usted mismo emite la transferencia.
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 respuesta es un 202 con dos cabeceras que conviene leer en vez de reconstruir: Location, la URL del propio pedido, y Retry-After, los segundos que hay que esperar antes de la primera consulta y entre consultas. El cuerpo es el pedido, normalmente con status en funded y send_before todavía en null: el dinero está reservado y la compra ha empezado.
send_before aparece cuando la energía se confirma en la cadena y el pedido llega a ready. Es una ventana de unos cuatro minutos, contada desde la última delegación confirmada, así que todos los ítems de un lote comparten un mismo plazo; lea el campo en vez de dar por hechos los cuatro minutos. Vigile también la aparición del campo y no la palabra ready: un pedido en el mode A se cumple con la entrega de energía y no con su transferencia, así que completed puede llegar antes de que usted haya enviado nada.
Dos rechazos merecen estar cableados antes del primer pedido real: 402 insufficient_balance, decidido antes de que se mueva dinero y con required_trx y available_trx dentro, y 422 invalid_address con details.reason en inactive_wallet: la cartera de origen nunca se activó, así que no hay cuenta a la que delegar (los fallos que hay detrás de esos dos).
La clave de idempotencia
POST /v1/orders exige una Idempotency-Key, y queda ligada a los bytes crudos del cuerpo y no al JSON ya interpretado. Los mismos bytes devuelven el pedido original; otro cuerpo bajo la misma clave es 409 idempotency_conflict y no un segundo pedido; una petición rechazada por la validación no gasta la clave. A tamaño de lote, eso es lo que convierte un tiempo de espera agotado de la red en una pregunta con respuesta.
Qué le dicen las cabeceras de límite de peticiones
Se cuentan tres contadores por clave de API: los pedidos a 120 por minuto, las peticiones de consulta a 600, y GET /v1/address-check a 60, porque cada fallo de su caché es una pregunta a la cadena. Toda respuesta de un contador con clave, también las correctas, lleva RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset, de modo que un cliente puede frenar antes del rechazo y no después; pasado el límite llega 429 rate_limited con Retry-After. Hay otro 429 que significa casi lo contrario: too_many_auth_failures, donde esperar no ayuda porque lo que se rechaza es la propia credencial. Ramifique por code, nunca por message.
Webhooks, para que el bucle no sea un sondeo
Registre un receptor con POST /v1/webhooks: la url tiene que ser https, resolver a un host público y no llevar credenciales. El secreto de firma se devuelve una sola vez, al crearlo, y una cuenta admite como mucho cinco endpoints activos. Suscríbase a lo que el flujo necesite — order.ready, order.completed, order.partially_completed, order.failed, más los de cada ítem, order.item.sent y order.item.expired. Cada entrega lleva X-NRG-Timestamp, X-NRG-Event-Id y X-NRG-Signature, un HMAC-SHA256 sobre la marca de tiempo, un punto y el cuerpo crudo: verifique contra los bytes que recibió y no contra un JSON que usted volvió a codificar, y deduplique por event_id. POST /v1/webhooks/{webhook_id}/test manda una entrega firmada de verdad por la ruta real e informa de lo que contestó su endpoint, sin coste.
Mode B: usted la firma, nosotros la emitimos
El mode b sustituye from y to por signed_tx, la transacción firmada en hexadecimal, y la emitimos en cuanto la energía llega: nadie se queda esperando una ventana de cuatro minutos. Lo que se acepta es estrecho a propósito: una llamada transfer del contrato de USDT y nada más, una sola firma del propietario, sin TRX adjuntos y sin multifirma, porque el conjunto de claves de un permiso vive en la cadena y puede cambiar sin que lo sepamos. La transacción necesita tres minutos de vida por delante cuando se crea el pedido, y su propia caducidad acorta la ventana: send_before nunca pasa de ese plazo menos un margen de emisión. Si no logramos retransmitirla a tiempo, el ítem se cierra como failed con broadcast_window_missed y la reserva vuelve entera.
Mode C: energía sin destinatario nombrado
El mode c toma from y kind, y ningún destinatario: es para la cartera que quiere tener lista antes de que el lote exista. kind es single o double, y acertar le toca a usted: sin destinatario no hay de dónde leer el volumen, así que un single donde hacía falta double deja la transferencia corta y la diferencia quema TRX. custom no se ofrece aquí a propósito, porque es el resultado de una simulación contra un contrato destinatario concreto. Los ítems llevan to: null, nunca llegan a sent y pasan a expired al cerrarse la ventana: se acabó el alquiler, que es el final normal y no un fallo — y se cobra, porque la energía se entregó.
Lo que nunca va en la petición
No hay ningún campo para una clave privada en ninguna parte del contrato, en ningún modo. El mode A nunca ve su transacción. El mode B ve una que usted ya firmó, y no podemos alterar ni un byte de ella sin romper esa firma; se guarda cifrada y se borra siete días después de que el pedido sea final. El mode C no tiene transacción que ver. Lo que se le entrega a la API son direcciones (el resto de lo que guardamos y lo que no).
Las partes que no necesitan clave
Los endpoints de consulta y el contrato no necesitan clave alguna, y su límite de peticiones va por IP y no por clave. GET /v1/tariff responde el precio de una unidad de energía en sun ahora mismo, la franja en curso, next_change_at y un horario de referencia: es lo que lee la página de precios en cada carga. GET /v1/market responde lo que publican de sí mismos los vendedores que vigilamos, cada cifra sellada con el momento en que se leyó y nuestro propio precio situado entre ellas, que es la página del mercado. Cite el endpoint y no una cifra: nuestro precio se recalcula cada pocos minutos.
El contrato en sí está en https://docs.nrg.market/openapi.yaml, y byte a byte el mismo documento en https://api.nrg.market/v1/contract.yaml: conviene saberlo, porque el host de la documentación está detrás de una capa que rechaza a algunos clientes programáticos antes de que la petición nos llegue. Allí el ETag es el SHA-256 del cuerpo, así que If-None-Match recibe un 304 cuando nada ha cambiado. Genere su cliente a partir de ese archivo: esta página es un resumen, y el archivo es aquello a lo que estamos obligados.