Developer Documentation
The Tribe Pay Merchant API lets you accept payments from your website or application. You initiate a payment session from your server, redirect your customer to a hosted checkout page, and receive the result via webhook or status query.
Card data is collected by the payment gateway directly — it never passes through Tribe Pay's servers or yours, satisfying PCI DSS SAQ-A.
Base URL
https://api.tribepay.com
All API requests must be made over HTTPS. All request and response bodies are JSON.
During development, replace https://api.tribepay.com with your local instance URL (e.g. http://127.0.0.1:8123) and use a pk_test_ key to avoid charging real cards.
Quick Start
Get a payment running in three steps.
Log in to the Tribe Pay merchant portal, go to Developer → API Keys, and copy your live key (pk_live_…) or test key (pk_test_…).
Send the order details and receive a checkout_url. Redirect your customer to that URL — Tribe Pay handles the card form.
After payment, the customer is sent to your return_url. Confirm the outcome by calling GET /api/pay/status/{order_id} or by listening for the payment.completed webhook event.
Authentication
All payment API requests authenticate using your API key in the X-API-Key header.
X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Key types
| Prefix | Mode | Behaviour |
|---|---|---|
| pk_live_… | live | Real money is charged. Payments are credited to your wallet. |
| pk_test_… | sandbox | No real money. Use test cards. Wallets are not credited. |
Keep your API key secret. Never expose it in client-side code, mobile apps, or public repositories. If a key is compromised, revoke it immediately from the merchant portal and generate a new one.
You can have up to 5 active keys at once. Label each key by environment or service (e.g. "Production Server", "Staging") for easy management.
Sandbox Mode
Use a pk_test_ key to run payments in sandbox mode. All requests hit real API endpoints — the only difference is that the payment gateway operates in test mode and no real funds move.
| Behaviour | Live | Sandbox |
|---|---|---|
| Real money charged | Yes | No |
| Wallet credited on success | Yes | No |
| Webhooks fired | Yes | Yes |
Response mode field | live | sandbox |
See Test Cards for card numbers to use on the sandbox checkout page.
Initiate Payment
Creates a checkout session and returns a hosted checkout URL. Call this from your server when a customer is ready to pay.
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| order_id | string | Required | Your unique order identifier. Max 100 characters. Must be unique per merchant. |
| amount | number | Required | Payment amount as a decimal. Minimum 1, maximum 1,000,000. |
| currency | string | Optional | ISO 4217 currency code (e.g. INR, USD, EUR). Defaults to INR. |
| customer_name | string | Optional | Customer's full name. Shown on the checkout page. |
| customer_email | string | Optional | Customer's email address. Used for payment receipts. |
| customer_phone | string | Optional | Customer's phone number including country code. |
| description | string | Optional | Short description of the purchase. Shown on checkout. Max 255 characters. |
| return_url | string | Required | URL where the customer is sent after payment (success or failure). Must be HTTPS in production. |
| cancel_url | string | Optional | URL when the customer cancels. Falls back to return_url if not provided. |
| webhook_url | string | Optional | One-time webhook URL for this payment only. Overrides any webhook configured in the portal for this request. |
Example request
curl -X POST https://api.tribepay.com/api/pay/initiate \
-H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"order_id": "ORD-2024-001",
"amount": 999.00,
"currency": "INR",
"customer_name": "Priya Sharma",
"customer_email": "priya@example.com",
"customer_phone": "+91 9876543210",
"description": "Premium Plan — 1 Month",
"return_url": "https://yoursite.com/payment/return",
"cancel_url": "https://yoursite.com/payment/cancel",
"webhook_url": "https://yoursite.com/webhooks/tribepay"
}'<?php
$payload = [
'order_id' => 'ORD-2024-001',
'amount' => 999.00,
'currency' => 'INR',
'customer_name' => 'Priya Sharma',
'customer_email' => 'priya@example.com',
'customer_phone' => '+91 9876543210',
'description' => 'Premium Plan — 1 Month',
'return_url' => 'https://yoursite.com/payment/return',
'cancel_url' => 'https://yoursite.com/payment/cancel',
];
$ch = curl_init('https://api.tribepay.com/api/pay/initiate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
header('Location: ' . $data['checkout_url']);
exit;const axios = require('axios');
const { data } = await axios.post(
'https://api.tribepay.com/api/pay/initiate',
{
order_id: 'ORD-2024-001',
amount: 999.00,
currency: 'INR',
customer_name: 'Priya Sharma',
customer_email: 'priya@example.com',
customer_phone: '+91 9876543210',
description: 'Premium Plan — 1 Month',
return_url: 'https://yoursite.com/payment/return',
cancel_url: 'https://yoursite.com/payment/cancel',
},
{ headers: { 'X-API-Key': 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' } }
);
res.redirect(data.checkout_url);import requests
response = requests.post(
'https://api.tribepay.com/api/pay/initiate',
json={
'order_id': 'ORD-2024-001',
'amount': 999.00,
'currency': 'INR',
'customer_name': 'Priya Sharma',
'customer_email': 'priya@example.com',
'customer_phone': '+91 9876543210',
'description': 'Premium Plan — 1 Month',
'return_url': 'https://yoursite.com/payment/return',
'cancel_url': 'https://yoursite.com/payment/cancel',
},
headers={'X-API-Key': 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
)
data = response.json()
return redirect(data['checkout_url'])Response 201 Created
{
"success": true,
"order_id": "ORD-2024-001",
"reference": "TRP-K7XB-NQ2A",
"amount": 999.00,
"currency": "INR",
"mode": "live",
"checkout_url": "https://api.tribepay.com/checkout/a8f3c2e1d0b4...",
"expires_at": "2024-07-22T15:30:00+00:00"
}| Field | Type | Description |
|---|---|---|
| reference | string | Tribe Pay's unique transaction reference (TRP-XXXX-XXXX). Store this alongside your order ID. |
| mode | string | live or sandbox depending on which key was used. |
| checkout_url | string | Redirect your customer here. The session expires in 30 minutes. |
| expires_at | string | ISO 8601 timestamp when the checkout URL expires. |
The checkout_url expires in 30 minutes. If the customer does not complete payment in time, the status becomes expired. Create a new session to let them retry.
Handle Return URL
After the customer pays (or cancels), Tribe Pay redirects them to your return_url with the following query parameters appended.
https://yoursite.com/payment/return
?status=completed
&order_id=ORD-2024-001
&reference=TRP-K7XB-NQ2A| Parameter | Values |
|---|---|
| status | completed · failed · cancelled · expired |
| order_id | Your original order ID. |
| reference | Tribe Pay reference code (TRP-XXXX-XXXX). |
Do not rely on return URL parameters alone to confirm payment. These can be manipulated in the browser. Always verify by calling GET /api/pay/status/{order_id} from your server or by processing a signed webhook event.
Recommended pattern
<?php
$orderId = $_GET['order_id'] ?? '';
$ch = curl_init("https://api.tribepay.com/api/pay/status/{$orderId}");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($data['status'] === 'completed') {
fulfil_order($orderId);
show_success_page();
} else {
show_failure_page($data['status']);
}Check Payment Status
Query the current status of any payment by its order_id.
curl https://api.tribepay.com/api/pay/status/ORD-2024-001 \
-H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<?php
$ch = curl_init('https://api.tribepay.com/api/pay/status/ORD-2024-001');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data['status'];const { data } = await axios.get(
'https://api.tribepay.com/api/pay/status/ORD-2024-001',
{ headers: { 'X-API-Key': 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' } }
);
console.log(data.status);response = requests.get(
'https://api.tribepay.com/api/pay/status/ORD-2024-001',
headers={'X-API-Key': 'pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
)
print(response.json()['status'])Response 200 OK
{
"success": true,
"order_id": "ORD-2024-001",
"reference": "TRP-K7XB-NQ2A",
"amount": 999.00,
"currency": "INR",
"status": "completed",
"mode": "live",
"paid_at": "2024-07-22T14:35:22+00:00"
}Webhooks
Webhooks are server-to-server notifications sent by Tribe Pay when a payment event occurs. They are the most reliable way to fulfil orders — unlike the return URL, webhooks are delivered even if the customer closes their browser.
Setup
Add a webhook endpoint in the merchant portal under Developer → Webhooks. Specify your URL and choose which events to receive. You'll receive a signing secret — save it, it's shown only once.
Your webhook endpoint must respond with HTTP 200 within 10 seconds. Acknowledge receipt first, then process the event asynchronously.
Events
Subscribe to * to receive all events now and in the future.
Payload format
{
"event": "payment.completed",
"timestamp": "2024-07-22T14:35:22+00:00",
"data": {
"order_id": "ORD-2024-001",
"reference": "TRP-K7XB-NQ2A",
"amount": 999.00,
"currency": "INR",
"status": "completed",
"mode": "live",
"paid_at": "2024-07-22T14:35:22+00:00"
}
}Verifying the signature
Every webhook includes an X-Tribe-Signature header. Verify it before processing to confirm the request came from Tribe Pay.
Always verify the signature. Anyone who knows your webhook URL can send fake events. Reject requests with a missing or invalid signature with 401.
<?php
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_TRIBE_SIGNATURE'] ?? '';
$signingSecret = getenv('TRIBE_WEBHOOK_SECRET');
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $signingSecret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Unauthorized');
}
$event = json_decode($rawBody, true);
http_response_code(200);
echo 'OK';
ob_flush(); flush();
if ($event['event'] === 'payment.completed') {
fulfil_order($event['data']['order_id']);
}
if ($event['event'] === 'payment.refunded') {
reverse_fulfilment($event['data']['order_id']);
}const crypto = require('crypto');
app.post('/webhooks/tribepay',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-tribe-signature'] ?? '';
const signingSecret = process.env.TRIBE_WEBHOOK_SECRET;
const expected = 'sha256=' + crypto
.createHmac('sha256', signingSecret)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
)) return res.status(401).send('Unauthorized');
res.status(200).send('OK');
const event = JSON.parse(req.body);
if (event.event === 'payment.completed') {
fulfilOrder(event.data.order_id);
}
}
);import hmac, hashlib, json, os
from flask import Flask, request, abort
SIGNING_SECRET = os.environ['TRIBE_WEBHOOK_SECRET']
@app.route('/webhooks/tribepay', methods=['POST'])
def tribepay_webhook():
signature = request.headers.get('X-Tribe-Signature', '')
raw_body = request.get_data()
expected = 'sha256=' + hmac.new(
SIGNING_SECRET.encode(), raw_body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
abort(401)
event = json.loads(raw_body)
if event['event'] == 'payment.completed':
fulfil_order(event['data']['order_id'])
return 'OK', 200Retry policy
If your endpoint does not respond with 200 within 10 seconds, Tribe Pay retries with exponential back-off:
| Attempt | Delay |
|---|---|
| 1st retry | 5 minutes |
| 2nd retry | 30 minutes |
| 3rd retry | 2 hours |
| 4th retry | 8 hours |
| 5th retry | 24 hours — final attempt |
Your handler may receive the same event more than once due to retries. Make order fulfilment idempotent — check if an order is already fulfilled before acting on a webhook.
Payment Statuses
| Status | Description | Terminal? |
|---|---|---|
| pending | Checkout session created. Customer has not yet reached the payment page. | No |
| processing | Customer redirected to the payment gateway. Awaiting confirmation. | No |
| completed | Payment captured successfully. Funds will be credited to your Tribe Pay wallet. | Yes |
| failed | Payment was declined, rejected by the bank, or an error occurred at the gateway. | Yes |
| expired | The 30-minute checkout window elapsed before the customer completed payment. | Yes |
| refunded | A completed payment was reversed. The amount is deducted from your wallet. | Yes |
Error Codes
Errors return a JSON object with a human-readable message. Validation errors also include an errors object.
{
"message": "The given data was invalid.",
"errors": {
"amount": ["The amount field is required."],
"return_url": ["The return url must be a valid URL."]
}
}HTTP status codes
X-API-Key. Check the key is active and correctly formatted.errors object for field-level details.Common errors & fixes
| Error message | Fix |
|---|---|
| No active payment gateway assigned | Ask your Tribe Pay admin to assign a gateway account to your merchant profile. |
| The order id has already been taken | Your order_id is not unique. Each payment must use a different value. |
| The return url field is required | Include a valid absolute URL in the return_url field. |
| Unauthenticated | The X-API-Key header is missing or the key has been revoked. |
Test Cards
Use these card numbers on the sandbox checkout page (any future expiry date, any CVV unless specified).
Cards that complete successfully
| Brand | Number | CVV | Expiry |
|---|---|---|---|
| Visa | 4200 0000 0000 0000 | Any 3 digits | Any future date |
| Visa | 4000 0000 0000 0051 | 745 | Any future date |
| Mastercard | 5101 0821 8725 6503 | 123 | Any future date |
| Mastercard | 5454 5454 5454 5454 | Any 3 digits | Any future date |
| Amex | 3755 1051 3169 537 | 123 | Any future date |
3D Secure test cards
| Brand | Number | CVV | Behaviour |
|---|---|---|---|
| Visa (3DS) | 4000 0000 0000 0002 | 237 | Triggers 3D Secure challenge, then completes |
Test cards only work with a pk_test_ API key. Using a test card number with a live key will result in a real declined charge.
Questions or issues? Contact your Tribe Pay account manager or open a support ticket from the merchant portal.