Pre-launch

API reference

The TujuPay API, field by field.

A predictable REST API over HTTPS. Requests are form-encoded or JSON, responses are always JSON, and every amount is an integer in sen.

◷ Sandbox opens to waitlist developers first. Live keys follow once TujuPay is licensed.

Basics

Base URL
https://api.tujupay.com/v1
Authentication
HTTP Basic with your secret key as the username
Amounts
Integers in sen. RM 189.00 is 18900
Currency
myr
Idempotency
Send an Idempotency-Key header on every POST. Keys are kept for 24 hours
Versioning
Send TujuPay-Version: 2026-10-01 to pin a version
Pagination
limit (1 to 100) and starting_after, returning has_more

The Payment object

A Payment represents one attempt by a customer to pay you. It moves through the statuses below.

FieldTypeDescription
idstringUnique ID, starting with pay_
statusenumrequires_payment, processing, succeeded, failed, expired or refunded
amountintegerAmount in sen
currencystringAlways myr
methodsarrayMethods offered at checkout, such as fpx and duitnow_qr
method_usedstringThe method the customer actually paid with
referencestringYour own order reference
checkout_urlstringWhere to send the customer to pay
payout_datedateThe working day this payment is paid out to you
created_attimestampWhen the payment was created, in ISO 8601

Payment statuses

  1. 1requires_paymentCreated and waiting for the customer to pay
  2. 2processingThe customer approved and the bank is confirming
  3. 3succeededPaid. Safe to fulfil the order
  4. 4failedDeclined by the bank or abandoned by the customer
  5. 5expiredNot paid within 30 minutes. Create a new payment to try again
  6. 6refundedFully refunded to the customer

Endpoints

POST/v1/payments

Create a payment

Creates a payment and returns a checkout_url to send the customer to.

Request

curl
curl https://api.tujupay.com/v1/payments \
  -u sk_test_51HxQ2...: \
  -H "Idempotency-Key: order-2214" \
  -d amount=18900 \
  -d currency=myr \
  -d "methods[]=fpx" \
  -d "methods[]=duitnow_qr" \
  -d reference=ORDER-2214 \
  -d return_url=https://yourshop.my/orders/2214

Response

JSON
{
  "id": "pay_3Kx9LmQ2",
  "status": "requires_payment",
  "amount": 18900,
  "currency": "myr",
  "methods": ["fpx", "duitnow_qr"],
  "reference": "ORDER-2214",
  "checkout_url": "https://pay.tujupay.com/c/3Kx9LmQ2",
  "payout_date": null,
  "created_at": "2026-10-09T10:42:00+08:00"
}
GET/v1/payments/{id}

Retrieve a payment

Returns the latest state of a payment. Useful as a fallback if you missed a webhook.

Request

curl
curl https://api.tujupay.com/v1/payments/pay_3Kx9LmQ2 \
  -u sk_test_51HxQ2...:

Response

JSON
{
  "id": "pay_3Kx9LmQ2",
  "status": "succeeded",
  "amount": 18900,
  "method_used": "fpx",
  "payout_date": "2026-10-09"
}
POST/v1/refunds

Refund a payment

Refunds all or part of a succeeded payment. Leave out amount to refund in full.

Request

curl
curl https://api.tujupay.com/v1/refunds \
  -u sk_test_51HxQ2...: \
  -H "Idempotency-Key: refund-2214-1" \
  -d payment=pay_3Kx9LmQ2 \
  -d amount=5000

Response

JSON
{
  "id": "re_7Pq1Xs",
  "payment": "pay_3Kx9LmQ2",
  "amount": 5000,
  "status": "processing"
}
GET/v1/payouts

List payouts

Lists payouts to your bank, newest first, with a statement for each.

Request

curl
curl "https://api.tujupay.com/v1/payouts?limit=2" \
  -u sk_test_51HxQ2...:

Response

JSON
{
  "data": [
    { "id": "po_1Tz", "amount": 320760, "status": "paid", "arrival_date": "2026-10-09" },
    { "id": "po_0Ym", "amount": 291840, "status": "paid", "arrival_date": "2026-10-08" }
  ],
  "has_more": true
}

Errors

Errors return a standard HTTP status and a JSON body with a type, a code and a message written for humans.

StatusCodeWhat it means
400invalid_requestA parameter is missing or wrong. The message says which
401unauthorizedThe API key is missing, wrong or revoked
404not_foundNo object with that ID in this mode
409idempotency_conflictThe same Idempotency-Key was used with different parameters
429rate_limitedToo many requests. Wait and retry with backoff
500server_errorSomething went wrong on our side. Safe to retry with the same key
JSON
{
  "error": {
    "type": "invalid_request",
    "code": "amount_too_small",
    "message": "amount must be at least 100 sen (RM 1.00).",
    "param": "amount"
  }
}