Merchant API
v1.0

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

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.

1
Register your business & get an API key

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_…).

2
Call /api/pay/initiate from your server

Send the order details and receive a checkout_url. Redirect your customer to that URL — Tribe Pay handles the card form.

3
Receive the result

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.

Header
X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key types

PrefixModeBehaviour
pk_live_…liveReal money is charged. Payments are credited to your wallet.
pk_test_…sandboxNo 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.

BehaviourLiveSandbox
Real money chargedYesNo
Wallet credited on successYesNo
Webhooks firedYesYes
Response mode fieldlivesandbox

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.

POST /api/pay/initiate

Request parameters

ParameterTypeRequiredDescription
order_idstringRequiredYour unique order identifier. Max 100 characters. Must be unique per merchant.
amountnumberRequiredPayment amount as a decimal. Minimum 1, maximum 1,000,000.
currencystringOptionalISO 4217 currency code (e.g. INR, USD, EUR). Defaults to INR.
customer_namestringOptionalCustomer's full name. Shown on the checkout page.
customer_emailstringOptionalCustomer's email address. Used for payment receipts.
customer_phonestringOptionalCustomer's phone number including country code.
descriptionstringOptionalShort description of the purchase. Shown on checkout. Max 255 characters.
return_urlstringRequiredURL where the customer is sent after payment (success or failure). Must be HTTPS in production.
cancel_urlstringOptionalURL when the customer cancels. Falls back to return_url if not provided.
webhook_urlstringOptionalOne-time webhook URL for this payment only. Overrides any webhook configured in the portal for this request.

Example request

bash
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
<?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;
javascript
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);
python
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

json
{
  "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"
}
FieldTypeDescription
referencestringTribe Pay's unique transaction reference (TRP-XXXX-XXXX). Store this alongside your order ID.
modestringlive or sandbox depending on which key was used.
checkout_urlstringRedirect your customer here. The session expires in 30 minutes.
expires_atstringISO 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.

example redirect
https://yoursite.com/payment/return
  ?status=completed
  &order_id=ORD-2024-001
  &reference=TRP-K7XB-NQ2A
ParameterValues
statuscompleted · failed · cancelled · expired
order_idYour original order ID.
referenceTribe 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
<?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.

GET /api/pay/status/{order_id}
bash
curl https://api.tribepay.com/api/pay/status/ORD-2024-001 \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
php
<?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'];
javascript
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);
python
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

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

payment.initiatedA checkout session was created. Payment has not been attempted yet.
payment.completedPayment was captured successfully. Safe to fulfil the order.
payment.failedPayment was declined or encountered an error.
payment.refundedA completed payment was reversed. Reverse fulfilment if applicable.

Subscribe to * to receive all events now and in the future.

Payload format

json
{
  "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
<?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']);
}
javascript
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);
    }
  }
);
python
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', 200

Retry policy

If your endpoint does not respond with 200 within 10 seconds, Tribe Pay retries with exponential back-off:

AttemptDelay
1st retry5 minutes
2nd retry30 minutes
3rd retry2 hours
4th retry8 hours
5th retry24 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

StatusDescriptionTerminal?
pendingCheckout session created. Customer has not yet reached the payment page.No
processingCustomer redirected to the payment gateway. Awaiting confirmation.No
completedPayment captured successfully. Funds will be credited to your Tribe Pay wallet.Yes
failedPayment was declined, rejected by the bank, or an error occurred at the gateway.Yes
expiredThe 30-minute checkout window elapsed before the customer completed payment.Yes
refundedA 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.

json — 422 example
{
  "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

400
Bad request — invalid parameters or a gateway error while creating the checkout.
401
Missing or invalid X-API-Key. Check the key is active and correctly formatted.
404
Order ID not found, or the order belongs to a different merchant account.
422
Validation failed. Check the errors object for field-level details.
500
Internal server error. Retry with exponential back-off. If it persists, contact support.

Common errors & fixes

Error messageFix
No active payment gateway assignedAsk your Tribe Pay admin to assign a gateway account to your merchant profile.
The order id has already been takenYour order_id is not unique. Each payment must use a different value.
The return url field is requiredInclude a valid absolute URL in the return_url field.
UnauthenticatedThe 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

BrandNumberCVVExpiry
Visa4200 0000 0000 0000Any 3 digitsAny future date
Visa4000 0000 0000 0051745Any future date
Mastercard5101 0821 8725 6503123Any future date
Mastercard5454 5454 5454 5454Any 3 digitsAny future date
Amex3755 1051 3169 537123Any future date

3D Secure test cards

BrandNumberCVVBehaviour
Visa (3DS)4000 0000 0000 0002237Triggers 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.