v1.0 · REST · JSON · Gift Card Trading & Purchasing
The PeerTupeer API gives developers and businesses programmatic access to buy gift cards, submit gift card trades, check balances, and manage webhooks. All responses are JSON.
There are two main flows:
Every request requires two headers:
| Header | Required | Description |
|---|---|---|
X-API-Key | Required | Your API key from the Merchant Dashboard |
X-API-Username | Optional | Your merchant slug or business email. Adds an extra layer of security when provided. |
Example headers
X-API-Key: ptp_live_abc123xyz... X-API-Username: yourcompany
ptp_live_. Sandbox keys start with ptp_test_ — use them to test without real transactions or wallet charges.
Generate keys at https://app.peertupeer.com/merchant/api-keys
https://app.peertupeer.com/api/v1
The fastest way to integrate: get your API key, pick a product, and place an order. Poll for the card code once it's ready.
<?php
$apiKey = 'ptp_live_YOUR_KEY';
$apiUsername = 'your-merchant-slug'; // optional
$base = 'https://app.peertupeer.com/api/v1';
// Step 1 — List available gift card products
$ch = curl_init($base . '/gift-cards');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'X-API-Username: ' . $apiUsername,
],
]);
$products = json_decode(curl_exec($ch), true);
curl_close($ch);
// Step 2 — Purchase a $50 Amazon USA card
$ch = curl_init($base . '/gift-cards');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => json_encode([
'product_id' => 1, // Amazon
'country' => 'USA',
'currency' => 'USD',
'face_value' => 50,
'quantity' => 1,
]),
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'X-API-Username: ' . $apiUsername,
'Content-Type: application/json',
],
]);
$order = json_decode(curl_exec($ch), true);
curl_close($ch);
$ref = $order['data']['reference']; // e.g. "GCAXXXXXXXX"
// Step 3 — Poll until ready (usually < 5 minutes)
do {
sleep(10);
$ch = curl_init($base . '/purchase-status?reference=' . $ref);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'X-API-Username: ' . $apiUsername,
],
]);
$status = json_decode(curl_exec($ch), true);
curl_close($ch);
} while (!$status['data']['ready']);
$cardCode = $status['data']['cards'][0]['code'];
echo "Card code: " . $cardCode;
All errors return success: false with an HTTP status code and a message.
| Code | Meaning |
|---|---|
400 | Bad request — missing or invalid parameters |
401 | Invalid or missing API key / username mismatch |
402 | Insufficient wallet balance |
404 | Resource not found |
409 | Conflict — e.g. duplicate reference |
422 | Validation error — see message for details |
500 | Server error |
// Error response example
{
"success": false,
"message": "Insufficient merchant wallet balance. Need GHS 155.00, have GHS 50.00."
}
Returns all available gift card products with rates and pricing. No auth required for this endpoint, but API key enables per-merchant pricing.
/api/v1/gift-cardscurl 'https://app.peertupeer.com/api/v1/gift-cards' \ -H 'X-API-Key: ptp_live_YOUR_KEY' \ -H 'X-API-Username: your-slug'
Response
{
"success": true,
"data": [
{
"id": 1,
"name": "Amazon",
"slug": "amazon",
"category": "retail",
"image_url": "https://app.peertupeer.com/uploads/gift_cards/amazon.png",
"rate_count": 3,
"min_rate_ghs": 14.5,
"stock_available": 0
}
]
}
Places a gift card order. The total GHS amount is deducted from your merchant wallet immediately. The card code is delivered within 5 minutes — poll /purchase-status or listen for the purchase.fulfilled webhook.
/api/v1/gift-cards| Parameter | Type | Required | Description |
|---|---|---|---|
product_id | integer | Yes | Product ID from GET /gift-cards |
country | string | Yes | Country code e.g. "USA", "UK", "Canada" |
currency | string | Yes | Currency e.g. "USD", "GBP" |
face_value | float | Yes | Card denomination e.g. 10, 25, 50, 100 |
quantity | integer | No | Number of cards (default 1, max 10) |
curl -X POST 'https://app.peertupeer.com/api/v1/gift-cards' \
-H 'X-API-Key: ptp_live_YOUR_KEY' \
-H 'X-API-Username: your-slug' \
-H 'Content-Type: application/json' \
-d '{"product_id":1,"country":"USA","currency":"USD","face_value":50,"quantity":1}'
Response
{
"success": true,
"message": "Order placed. Card will be ready within 5 minutes.",
"data": {
"reference": "GCAXXXXXXXX",
"purchase_id": 42,
"status": "pending",
"card_status": "pending",
"quantity": 1,
"face_value": 50,
"currency": "USD",
"country": "USA",
"buy_rate": 14.5,
"base_ghs": 725.00,
"fee_ghs": 18.13,
"total_ghs": 743.13,
"note": "Poll GET /api/v1/purchase-status?reference=GCAXXXXXXXX"
}
}
Poll this endpoint after placing an order to check when the card code is ready. Alternatively, set up a purchase.fulfilled webhook to receive a push notification.
/api/v1/purchase-status?reference=GCAXXXXXXXXcurl 'https://app.peertupeer.com/api/v1/purchase-status?reference=GCAXXXXXXXX' \ -H 'X-API-Key: ptp_live_YOUR_KEY'
Response when ready
{
"success": true,
"message": "Card is ready.",
"data": {
"reference": "GCAXXXXXXXX",
"card_status": "ready",
"ready": true,
"cards": [
{ "code": "XXXX-XXXX-XXXX-XXXX", "pin": null, "expiry": null }
]
}
}
// Response when still pending
{
"success": true,
"message": "Card is being processed.",
"data": { "reference": "GCAXXXXXXXX", "card_status": "pending", "ready": false }
}
Returns all active buy/sell rates. No authentication required.
/api/v1/ratescurl 'https://app.peertupeer.com/api/v1/rates'
Submit a gift card for review and receive GHS payout once approved. Requires multipart form data with card images.
/api/v1/trades| Parameter | Type | Required | Description |
|---|---|---|---|
card_type_id | integer | Yes | Card type ID from /rates |
country | string | Yes | "USA", "UK", "Canada" etc. |
currency | string | Yes | "USD", "GBP" etc. |
card_amount | float | Yes | Face value of card |
front_image | file | Yes | Front image (JPG/PNG, max 10MB) |
back_image | file | Yes | Back image (JPG/PNG, max 10MB) |
quantity | integer | No | Number of cards (default 1) |
card_number | string | No | Card number/PIN if available |
receipt_image | file | No | Purchase receipt |
notes | string | No | Additional notes |
curl -X POST 'https://app.peertupeer.com/api/v1/trades' \ -H 'X-API-Key: ptp_live_YOUR_KEY' \ -F 'card_type_id=1' \ -F 'country=USA' \ -F 'currency=USD' \ -F 'card_amount=100' \ -F 'front_image=@/path/to/front.jpg' \ -F 'back_image=@/path/to/back.jpg'
Response
{
"success": true,
"data": {
"reference": "PTP1A2B3C4D5E",
"status": "pending",
"card_amount": 100,
"currency": "USD",
"gross_payout_ghs": 850.00,
"fee_ghs": 21.25,
"net_payout_ghs": 828.75
}
}
/api/v1/trade-status?reference=PTP...curl 'https://app.peertupeer.com/api/v1/trade-status?reference=PTP1A2B3C4D5E' \ -H 'X-API-Key: ptp_live_YOUR_KEY'
/api/v1/walletcurl 'https://app.peertupeer.com/api/v1/wallet' \ -H 'X-API-Key: ptp_live_YOUR_KEY'
Response
{
"success": true,
"data": {
"currency": "GHS",
"available_balance": 5420.00,
"pending_balance": 250.00,
"total_earned": 18000.00,
"total_withdrawn": 12580.00
}
}
Withdraw your merchant wallet balance via Mobile Money or bank transfer.
/api/v1/withdrawals| Parameter | Type | Required | Description |
|---|---|---|---|
amount | float | Yes | Amount in GHS |
method | string | Yes | mtn_momo, telecel_cash, airtel_tigo, bank_transfer |
account_name | string | Yes | Name on the account |
account_number | string | Yes | Phone or account number |
bank_name | string | Cond. | Required for bank_transfer |
curl -X POST 'https://app.peertupeer.com/api/v1/withdrawals' \
-H 'X-API-Key: ptp_live_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"amount":500,"method":"mtn_momo","account_name":"John Doe","account_number":"0241234567"}'
Register a URL to receive real-time POST notifications when events happen. Create webhooks at https://app.peertupeer.com/merchant/webhooks.
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PEERTUPEER_SIGNATURE'] ?? '';
$secret = 'your_webhook_secret';
if (!hash_equals(hash_hmac('sha256', $payload, $secret), $signature)) {
http_response_code(401);
exit('Unauthorized');
}
$event = json_decode($payload, true);
$type = $event['event']; // e.g. "purchase.fulfilled"
if ($type === 'purchase.fulfilled') {
$ref = $event['data']['reference'];
$cards = $event['data']['cards'];
// Deliver card codes to your customer
}
| Event | When it fires |
|---|---|
trade.created | New trade submitted via API |
trade.processing | Trade moved to Under Review or Processing |
trade.completed | Trade approved — wallet credited |
trade.rejected | Trade rejected |
withdrawal.completed | Withdrawal paid out |
withdrawal.rejected | Withdrawal rejected |
purchase.fulfilled | Gift card order fulfilled — codes ready |
rate.updated | An exchange rate was updated |
{
"event": "purchase.fulfilled",
"timestamp": 1717000000,
"data": {
"reference": "GCAXXXXXXXX",
"product_id": 1,
"country": "USA",
"currency": "USD",
"face_value": 50,
"quantity": 1,
"total_ghs": 743.13,
"fulfilled_at": "2026-06-01 14:30:00",
"cards": [
{ "code": "XXXX-XXXX-XXXX-XXXX", "pin": null, "expiry": null }
]
}
}
Subscribe to get notified when exchange rates change.
/api/v1/rate-updatescurl -X POST 'https://app.peertupeer.com/api/v1/rate-updates' \
-H 'X-API-Key: ptp_live_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"url":"https://yoursite.com/webhooks/rates"}'
ptp_test_ to test. No real wallet charges. Card codes return as SANDBOX-XXXXXXXX-TEST./api/v1/sandbox?action=test-cardscurl 'https://app.peertupeer.com/api/v1/sandbox?action=test-cards' \ -H 'X-API-Key: ptp_test_YOUR_SANDBOX_KEY'
Need help? Contact support@peertupeer.com or message us on WhatsApp.