Skip to main content
← Back to documentation

API reference

REST endpoints for the DHRU plugin and direct integrations.

API reference

Base URL: https://triapay.net. Server-to-server requests authenticate with Authorization: Bearer <api_key>. Browser sessions use the cookie set by /auth/login plus a CSRF token from /auth/csrf.

Authentication

Two key tiers per account:

Prefix Use
pk_live_* Production. Cannot be revealed after creation. Rotate to replace.
pk_test_* Sandbox. Revealable from the dashboard. Sandbox-only endpoints.

Rotate keys and webhook secrets from the Integration page. Rotation requires email OTP.

Create order

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 Type Notes
invoiceId int Your DHRU invoice id.
userId int DHRU user id for credit attribution.
baseAmount string Decimal string. A small amount-suffix is added for crypto chains.
currency string Source currency.
chain enum trc20 | bep20 | binance_pay. BEP20 and TRC20 also accept Binance internal (off-chain) transfers to the same deposit address.
asset enum USDT | USDC. TRC20 is USDT-only.
idempotencyKey string UUID. Repeated requests with the same payload return the same order.
returnUrl string Redirect target after the order ends.

Response

{
  "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"
}

Redirect the customer to checkoutUrl. Use expectedAmount as the exact amount the customer must send.

Order status

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"
}

Order states form a black-box state machine:

  • pending — awaiting payment.
  • matched — funds received, credit in progress.
  • credited — terminal success. Webhook acknowledged.
  • expired — terminal. Customer did not pay in time.
  • failed — terminal. Webhook delivery exhausted retries.
  • overpaid — terminal. Customer sent more than expected. Order is credited; flagged for manual review.

Late arrivals (chain settlement after expiresAt) are not auto-credited. Recover them from Admin → Orphan transactions.

Sandbox helpers

Available with pk_test_* only. Force terminal states without waiting for chain settlement:

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

Empty body. Returns the updated order. Sandbox webhooks include X-Payment-Mode: sandbox; the bundled DHRU plugin short-circuits these without crediting any invoice.

Customer-facing checkout

Token-only auth. Used by the hosted checkout page:

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

select-method body: {"chain": "bep20", "asset": "USDT"}. Returns the order with deposit address, expected amount, QR data URI, and match code.

Errors

JSON envelope, HTTP status reflects the class:

{ "error": "invalid_credentials", "code": "unauthorized" }
HTTP code When
400 validation_error Bad payload shape, missing required fields.
401 unauthorized Missing or invalid bearer / session.
403 forbidden IP not allowlisted, sandbox-only on a live key.
404 not_found Token expired, idempotency key unknown.
409 conflict Idempotency-key reused with a different payload.
429 rate_limited Honor the Retry-After header (seconds).
500 internal Server error. Retry with backoff.

Rate limits are enforced per account. Respect Retry-After on every 429.

Idempotency

Every state-changing request takes an idempotencyKey. Repeating the same key with the same payload returns the original order. Repeating the same key with a different payload returns:

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

Generate the key as a UUIDv4 per invoice and persist it on your side so retries after a network failure do not double-charge.


Need more?

Anything beyond this page is available under partner agreement. Reach us via WhatsApp on the homepage.