Saltar al contenido principal
← Volver a la documentación

Referencia de API

Endpoints REST para el plugin DHRU e integraciones directas.

Referencia de API

Base URL: https://triapay.net. Las solicitudes server-to-server se autentican con Authorization: Bearer <api_key>. Las sesiones de navegador usan la cookie establecida por /auth/login más un token CSRF de /auth/csrf.

Autenticación

Dos niveles de clave por cuenta:

Prefijo Uso
pk_live_* Producción. No se puede revelar tras la creación. Rota para reemplazar.
pk_test_* Sandbox. Visible desde el dashboard. Solo para endpoints de sandbox.

Rota claves y webhook secrets desde la página Integration. La rotación requiere email OTP.

Crear orden

POST /api/v1/orders
Authorization: Bearer pk_live_...
Content-Type: application/json

{
  "invoiceId": 12345,
  "userId": 678,
  "baseAmount": "10.00",
  "currency": "USD",
  "chain": "bep20",
  "asset": "USDT",
  "idempotencyKey": "01HT8X1V...-uuid",
  "returnUrl": "https://shop.example.com/orders/12345"
}
Field Tipo Notas
invoiceId int Tu invoice id de DHRU.
userId int User id de DHRU para atribución del crédito.
baseAmount string String decimal. Se agrega un pequeño sufijo al monto para crypto chains.
currency string Moneda de origen.
chain enum trc20 | bep20 | binance_pay. BEP20 y TRC20 también aceptan transferencias internas (off-chain) de Binance a la misma dirección de depósito.
asset enum USDT | USDC. TRC20 acepta solo USDT.
idempotencyKey string UUID. Las solicitudes repetidas con el mismo payload devuelven la misma orden.
returnUrl string Destino de redirect cuando la orden finaliza.

Respuesta

{
  "orderId": 4711,
  "checkoutToken": "ck_a8f3...",
  "checkoutUrl": "https://triapay.net/checkout/ck_a8f3...",
  "expectedAmount": "10.0001",
  "matchCode": 1,
  "expiresAt": "2026-05-08T05:30:00Z",
  "status": "pending"
}

Redirige al cliente a checkoutUrl. Usa expectedAmount como el monto exacto que el cliente debe enviar.

Estado de la orden

GET /api/v1/orders/{idempotencyKey}/status
Authorization: Bearer pk_live_...
{
  "orderId": 4711,
  "status": "credited",
  "txHash": "0xabc...",
  "matchedAmount": "10.0001",
  "creditedAt": "2026-05-08T05:18:42Z"
}

Los estados de la orden conforman una state machine black-box:

  • pending — esperando pago.
  • matched — fondos recibidos, crédito en proceso.
  • credited — éxito terminal. Webhook confirmado.
  • expired — terminal. El cliente no pagó a tiempo.
  • failed — terminal. La entrega del webhook agotó los reintentos.
  • overpaid — terminal. El cliente envió más de lo esperado. La orden se acredita y queda marcada para revisión manual.

Las llegadas tardías (liquidación de la chain después de expiresAt) no se acreditan automáticamente. Recupéralas desde Admin → Orphan transactions.

Helpers de sandbox

Disponibles solo con pk_test_*. Fuerza estados terminales sin esperar la liquidación de la chain:

POST /api/v1/sandbox/orders/{idempotencyKey}/force-match
POST /api/v1/sandbox/orders/{idempotencyKey}/force-credit
POST /api/v1/sandbox/orders/{idempotencyKey}/force-expire
POST /api/v1/sandbox/webhook/replay

Body vacío. Devuelve la orden actualizada. Los webhooks de sandbox incluyen X-Payment-Mode: sandbox; el plugin DHRU incluido los corta sin acreditar ninguna factura.

Checkout del cliente

Autenticación solo por token. Usado por la página de checkout alojada:

GET  /api/v1/checkout/{token}/status
GET  /api/v1/checkout/{token}/methods
POST /api/v1/checkout/{token}/select-method

Body de select-method: {"chain": "bep20", "asset": "USDT"}. Devuelve la orden con dirección de depósito, monto esperado, QR data URI y match code.

Errores

Envelope JSON; el status HTTP refleja la clase:

{ "error": "invalid_credentials", "code": "unauthorized" }
HTTP code Cuándo
400 validation_error Payload con forma incorrecta o campos requeridos faltantes.
401 unauthorized Bearer o sesión ausente o inválida.
403 forbidden IP no está en allowlist, key live usada en endpoint solo de sandbox.
404 not_found Token expirado, idempotency key desconocida.
409 conflict Idempotency-key reutilizada con un payload distinto.
429 rate_limited Respeta el header Retry-After (segundos).
500 internal Error del servidor. Reintenta con backoff.

Los rate limits se aplican por cuenta. Respeta Retry-After en cada 429.

Idempotencia

Toda solicitud que cambia estado requiere un idempotencyKey. Repetir la misma key con el mismo payload devuelve la orden original. Repetir la misma key con un payload distinto devuelve:

{ "error": "idempotency_payload_mismatch", "code": "conflict" }

Genera la key como un UUIDv4 por factura y persístela de tu lado para que los reintentos tras una falla de red no produzcan un doble cargo.


¿Necesitas más?

Cualquier cosa más allá de esta página está disponible bajo acuerdo de socio. Contáctanos por WhatsApp en la página de inicio.