API reference
Payments
A payment is one attempt to collect money from a customer. You create it, send the customer to its checkout_url, and then follow it until it succeeds, fails, is cancelled or expires.
The payment object#
{
"id": "pay_r3QA7YeEEBY3ABp3e2zS8iq9",
"object": "payment",
"status": "succeeded",
"amount": "340.00",
"amount_refunded": "0.00",
"currency": "AED",
"fee": "7.65",
"net": "332.35",
"reference": "order-1001",
"description": "Blue mug",
"customer_email": "buyer@example.com",
"metadata": { "cart_id": "42" },
"checkout_url": null,
"card": { "brand": "VISA", "last4": "4242", "country": "AE" },
"failure_message": null,
"livemode": false,
"created_at": "2026-10-20T10:00:00.000Z",
"paid_at": "2026-10-20T10:02:31.000Z"
}
| Field | Details |
|---|---|
idstring | The payment id. Starts with pay_. |
objectstring | Always "payment". |
statusstring | pending, succeeded, failed, cancelled or expired. See Statuses. |
amountstring | The amount in AED with two decimals, such as "340.00". |
amount_refundedstring | How much has been refunded so far (refunds that have succeeded). "0.00" if none. |
currencystring | Always "AED". |
feestring or null | The TigerPay fee. null until the payment succeeds. See Pricing. |
netstring or null | amount minus fee. null until the payment succeeds. |
referencestring | Your own order id, as you sent it. |
descriptionstring or null | The description you sent. |
customer_emailstring or null | The customer email you sent. |
metadataobject | Your key-value pairs. {} if you sent none. |
checkout_urlstring or null | Where to send the customer to pay. Only set while the status is pending; null after that. |
cardobject or null | { brand, last4, country } once the card is known. country is the country that issued the card. null before that. |
failure_messagestring or null | A short reason when the payment failed or expired. |
livemodeboolean | true for live payments, false for test payments. |
created_atstring | When the payment was created. ISO 8601, UTC. |
paid_atstring or null | When the payment succeeded. null before that. |
Statuses#
| Status | Meaning |
|---|---|
pending | Created. Waiting for the customer to pay. checkout_url is set. |
succeeded | The customer paid. fee, net, card and paid_at are set. You can refund it. |
failed | The payment did not go through, or could not be created. failure_message says why. |
cancelled | The payment was cancelled. |
expired | The customer did not pay in time. Create a new payment if they still want to buy. |
A payment normally ends in one of succeeded, failed, cancelled or expired.
A late success is possible
If the payment provider reports a payment as paid after TigerPay had marked it failed, cancelled or expired, the payment moves to succeeded and you get a payment.succeeded webhook. Always act on the latest status. If you already cancelled the order on your side, refund the payment or reopen the order.
Create a payment#
Creates a payment and returns it with a checkout_url. Send the customer there to pay.
Request body#
| Field | Details |
|---|---|
amountstring required | Amount in AED with exactly two decimals, such as "340.00". Minimum "2.00", maximum "10000000.00". Digits and one decimal point only: no commas, spaces, leading zeros or currency symbol. |
currencystring required | Must be "AED". |
referencestring required | Your own order id. 1 to 64 characters. It does not have to be unique, so you can create a new payment for the same order after a failed attempt. |
success_urlstring required | Where the customer is sent after checkout. Must be https, up to 512 characters, with no username or password in it. |
cancel_urlstring required | Same rules as success_url. Please read the note below: the customer is not sent to this URL today. |
descriptionstring | Up to 500 characters. |
customer_emailstring | A valid email address, up to 254 characters. |
metadataobject | Your own key-value pairs. Up to 20 keys. Each key is 1 to 40 characters. Each value must be a string of up to 500 characters. We send it back on the payment and in webhooks. |
success_url and cancel_url are both required. A request that leaves either one out is rejected with a 400 validation error. Unknown fields are rejected with a 400 error too, so a typo in a field name is caught straight away.
The customer always returns to success_url
The hosted payment page supports one return address. After checkout, the customer is sent to success_url whatever the outcome: paid, failed or not finished. cancel_url is required and is stored with the payment, but there is no separate cancel redirect.
So on your success_url page, do not say "thank you, paid". Look up the payment (or wait for the webhook) and show the real result.
Example#
curl https://api.tigerpay.app/v1/payments \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001" \
-d '{
"amount": "340.00",
"currency": "AED",
"reference": "order-1001",
"description": "Blue mug",
"customer_email": "buyer@example.com",
"success_url": "https://shop.example.com/thanks",
"cancel_url": "https://shop.example.com/cart",
"metadata": { "cart_id": "42" }
}'
const response = await fetch("https://api.tigerpay.app/v1/payments", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TIGERPAY_SECRET_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order-1001",
},
body: JSON.stringify({
amount: "340.00",
currency: "AED",
reference: "order-1001",
success_url: "https://shop.example.com/thanks",
cancel_url: "https://shop.example.com/cart",
}),
});
const payment = await response.json();
<?php
$ch = curl_init('https://api.tigerpay.app/v1/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('TIGERPAY_SECRET_KEY'),
'Content-Type: application/json',
'Idempotency-Key: order-1001',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => '340.00',
'currency' => 'AED',
'reference' => 'order-1001',
'success_url' => 'https://shop.example.com/thanks',
'cancel_url' => 'https://shop.example.com/cart',
]),
]);
$payment = json_decode(curl_exec($ch), true);
curl_close($ch);
Response: 200 with the payment object, status pending.
Possible errors#
| Code | When |
|---|---|
parameter_HTTP 400 | A field is missing or wrong. The message names the field, for example amount: must be a decimal string with two decimals, such as "340.00". |
invalid_HTTP 400 | You sent a field that does not exist. The message lists it. |
invalid_HTTP 400 | The body is not a JSON object. |
provider_HTTP 502 | The payment could not be created. Check your details and try again. |
provider_HTTP 502 | A temporary problem on our side. Retry. Nobody can pay for the failed attempt, because you never received a checkout_url for it. |
Retrieve a payment#
Returns the payment object for a pay_ id.
curl https://api.tigerpay.app/v1/payments/pay_r3QA7YeEEBY3ABp3e2zS8iq9 \
-H "Authorization: Bearer sk_test_YOUR_KEY"
- If the payment is still
pendingand is more than 2 minutes old, TigerPay checks its latest state before it answers. So this call can show a result even if a webhook has not reached you yet. - If the id does not exist, or belongs to another account or the other mode, you get
404with coderesource_missing.
Webhooks are the best way to learn about a result. Use this call to double-check, or to catch up after your server was down.
List payments#
Returns your payments, newest first. A test key lists test payments and a live key lists live payments.
| Query parameter | Details |
|---|---|
limitinteger | How many payments to return. 1 to 100. Default 10. |
starting_afterstring | A payment id. Returns the payments that come after it (older ones). Use the last id of the previous page. |
statusstring | Only payments with this status: pending, succeeded, failed, cancelled or expired. |
curl "https://api.tigerpay.app/v1/payments?limit=2&status=succeeded" \
-H "Authorization: Bearer sk_test_YOUR_KEY"
{
"object": "list",
"data": [
{ "id": "pay_r3QA7YeEEBY3ABp3e2zS8iq9", "object": "payment", "status": "succeeded", "…": "…" },
{ "id": "pay_kY9pF34Qy6nB3Wwd25rq4f5z", "object": "payment", "status": "succeeded", "…": "…" }
],
"has_more": true
}
If has_more is true, ask for the next page with starting_after set to the id of the last payment you received:
curl "https://api.tigerpay.app/v1/payments?limit=2&status=succeeded&starting_after=pay_kY9pF34Qy6nB3Wwd25rq4f5z" \
-H "Authorization: Bearer sk_test_YOUR_KEY"
An unknown query parameter, or a starting_after that is not one of your payments, gives 400 parameter_invalid.
Cancel a payment#
Cancels a payment that is still pending, so the customer can no longer pay it. No body is needed. TigerPay sends a payment.cancelled webhook.
curl -X POST https://api.tigerpay.app/v1/payments/pay_kY9pF34Qy6nB3Wwd25rq4f5z/cancel \
-H "Authorization: Bearer sk_test_YOUR_KEY"
It returns the payment with status cancelled and checkout_url set to null.
- Only
pendingpayments can be cancelled. Any other status gives400 payment_not_cancellable. If the customer pays at the same moment, the request can fail with this error. Fetch the payment to see its real status. - To give money back for a payment that succeeded, use a refund.
Money maths#
- Amounts are strings so that no rounding error can creep in. Do not turn them into floating-point numbers. Work in fils (
"340.00"is 34000 fils) or use a decimal library. - The fee is worked out in whole fils and rounded half up. Example: AED 10.10 on a UAE card at 2.25% is 22.725 fils, so the fee is 23 fils,
"0.23".