Skip to content

Developers

Built by people who have integrated a payment API before

Idempotency keys that work, errors that say what went wrong, webhooks you do not have to poll around, and a sandbox that behaves like production. None of that is remarkable. It is just frequently missing.

Principles

What we committed to

These are properties of the API rather than features of a plan. They apply to every account.

Idempotency on every write

Send an Idempotency-Key header and a replayed request returns the original result instead of creating a second transaction.

Predictable errors

Every failure returns a stable machine-readable code alongside a human-readable message. Codes do not change between releases.

Webhooks over polling

State changes are pushed to your endpoint, signed so you can verify they came from us. Nothing requires a polling loop.

Versioned, not broken

Breaking changes ship behind a new version. Your integration keeps working against the version you built on.

Sandbox parity

The sandbox exposes the same endpoints, the same payloads and the same error codes as production, with no live funds.

Paise, not rupees

Amounts are integers in the smallest currency unit. No floating point anywhere near money.

Webhooks

Verify the signature, acknowledge fast

Every webhook is signed with HMAC-SHA256 over the raw body. Verify before you trust it, return a 2xx quickly, and do the work asynchronously — we retry anything that is not acknowledged.

Events

  • payment.captured

    Funds captured against an order

  • payment.failed

    Payment failed permanently, with a reason code

  • refund.processed

    Refund submitted to the network

  • payout.queued

    Payout accepted and awaiting processing

  • payout.processed

    Payout has left the account

  • payout.failed

    Payout rejected, with a reason code

  • payout.reversed

    Payout returned by the beneficiary bank

  • virtual_account.credited

    Inbound credit received and attributed

  • settlement.processed

    Settlement sent to your bank account

webhook.js
// Verify the signature before trusting the payload.
import crypto from 'node:crypto'

export function verify(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')

  // Constant-time compare — a plain === leaks timing information.
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature),
  )
}

app.post('/webhooks/trustpay', (req, res) => {
  if (!verify(req.rawBody, req.get('X-TrustPay-Signature'), SECRET)) {
    return res.sendStatus(401)
  }

  const event = JSON.parse(req.rawBody)

  // Acknowledge fast, process asynchronously. We retry on non-2xx.
  queue.push(event)
  res.sendStatus(200)
})

Endpoints

The surface you will actually use

POST/v1/orders

Create an order to collect against

POST/v1/payments/:id/capture

Capture an authorised payment

POST/v1/refunds

Refund a payment in full or in part

POST/v1/payouts

Send a single payout

POST/v1/payouts/batch

Submit a batch of payouts

POST/v1/virtual-accounts

Issue a virtual account for a customer

GET/v1/transactions

Query and export transactions

GET/v1/settlements

Retrieve settlement records

Errors

What a failure looks like

A stable code to switch on, the offending field, a request_id to quote at support, and an explicit retryable flag so you are not guessing.

400 Bad Request
{
  "error": {
    "code": "payout_account_invalid",
    "message": "Beneficiary account number failed validation",
    "field": "account.number",
    "request_id": "req_9f2b41c8",
    "retryable": false
  }
}

SDKs

Or just use HTTP

Node.js

npm install @trustpay/node

Python

pip install trustpay

PHP

composer require trustpay/trustpay-php

Java

Maven and Gradle artifacts

React / React Native

Drop-in checkout components

REST

Everything is available over plain HTTP if you prefer

Questions

Integration, answered

How long does integration usually take?

A basic collection flow is typically a day of work against the sandbox. Payouts are faster because you can run them from the dashboard without any code while the integration is still being built.

Do you have a sandbox?

Yes, with the same endpoints, payloads and error codes as production and no live funds. Test credentials are issued at onboarding rather than after go-live.

How are webhooks secured?

Each webhook carries an HMAC-SHA256 signature computed over the raw request body using your webhook secret. Verify it with a constant-time comparison before acting on the payload.

What happens if my webhook endpoint is down?

We retry with exponential backoff over an extended window. Events are also queryable through the API, so a prolonged outage does not mean lost state.

Are amounts in rupees or paise?

Paise. All amounts are integers in the smallest currency unit, which avoids floating-point rounding on money.

Get sandbox credentials

Test keys are issued at onboarding, so you can build against the real API surface before anything goes live.