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.