Everything you need to integrate PingBacks into your hosting platform. Three core endpoints, JWT auth, and HMAC-signed webhooks.
https://api.pingbacks.io
All endpoints return JSON. Include the Content-Type: application/json header for POST/PUT requests.
PingBacks supports two authentication methods — API Keys for server-to-server integration and JWT Bearer Tokens for user-facing dashboards.
Used by providers for all transactional endpoints (/earn, /balance, /redeem). Your API key is generated when your provider account is approved.
# Include in every request header: X-PingBacks-API-Key: pb_live_8f391a2b3c4d5e6f7a8b9c0d1e2f3a4b
API keys are hashed with SHA-256 before storage. Never expose your key in client-side code.
Used by provider dashboards and customer portals. Obtain a token via /api/auth/login/tenant or /api/auth/login/user. Tokens expire after 24 hours.
# Include in every request header: Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Every registered customer receives a unique Ping-ID (format: PB-XXXXXXXXXXXX). This is their loyalty card number — they enter it during checkout, and you send it with your API calls. No need to collect or store email addresses.
// Customer enters Ping-ID at checkout
POST /api/v1/earn
{ "ping_id": "PB-A3F8K2M9X", ... }// Fallback for legacy integrations
POST /api/v1/earn
{ "customer_email": "kunde@example.de", ... }/api/v1/earnCredit points to a customer after a successful payment. Idempotent — sending the same invoice_id twice returns a 409 Conflict.
| Field | Type | Required | Description |
|---|---|---|---|
ping_id | string | ✓* | Customer's Ping-ID (e.g. PB-A3F8K2M9X) |
customer_email | string | * | Customer's email (alternative to ping_id) |
tenant_customer_id | string | ✓ | Your internal customer ID |
invoice_id | string | ✓ | Unique invoice/order ID (idempotency key) |
items[].category | string | ✓ | Product category: hosting, domain, server, addon |
items[].amount_eur | number | ✓ | Amount in euros (e.g. 49.90) |
* Either ping_id or customer_email is required.
curl -X POST https://api.pingbacks.io/api/v1/earn \
-H "Content-Type: application/json" \
-H "X-PingBacks-API-Key: pb_live_8f391a..." \
-d '{
"ping_id": "PB-A3F8K2M9X",
"tenant_customer_id": "cust_12345",
"invoice_id": "inv_99812",
"items": [
{ "category": "hosting", "amount_eur": 49.90 },
{ "category": "domain", "amount_eur": 14.90 }
]
}'{
"status": "success",
"pingbacks_user_id": "8040dd4c-6929-4741-8fd6-69386c308d2f",
"points_earned": 648,
"new_global_balance": 12850
}Points are calculated as: floor(amount_eur × multiplier). Each provider configures their own multipliers per category. Example with multiplier 10: €14.90 → 149 points.
/api/v1/balanceLook up a customer's current point balance. Use this to display points in your customer panel.
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | * | Customer's email address |
ping_id | string | * | Customer's Ping-ID (alternative) |
curl "https://api.pingbacks.io/api/v1/balance?ping_id=PB-A3F8K2M9X" \ -H "X-PingBacks-API-Key: pb_live_8f391a..."
{
"customer_email": "developer@agency-xyz.de",
"ping_id": "PB-A3F8K2M9X",
"global_balance": 12850,
"status": "linked"
}/api/v1/redeem/invoiceRedeem a customer's points to pay for an invoice. Deducts points from the global wallet. Triggers a signed webhook to the provider.
| Field | Type | Required | Description |
|---|---|---|---|
ping_id | string | ✓* | Customer's Ping-ID |
customer_email | string | * | Customer's email (alternative) |
points_to_redeem | integer | ✓ | Number of points to redeem (positive) |
invoice_id | string | ✓ | Invoice ID this redemption applies to |
curl -X POST https://api.pingbacks.io/api/v1/redeem/invoice \
-H "Content-Type: application/json" \
-H "X-PingBacks-API-Key: pb_live_8f391a..." \
-d '{
"ping_id": "PB-A3F8K2M9X",
"points_to_redeem": 1000,
"invoice_id": "inv_99850"
}'{
"status": "success",
"points_redeemed": 1000,
"equivalent_value_eur": 10.00,
"remaining_global_balance": 11850
}1 PingBack = €0.01. Redemption is atomic. Returns 400 INSUFFICIENT_BALANCE on low credits.
When a customer redeems points at your store, PingBacks sends a signed HTTP POST to your configured webhook URL. This allows you to automatically credit the invoice in your billing system.
POST <your-webhook-url>
Content-Type: application/json
X-PingBacks-Signature: <HMAC-SHA256-hex>
{
"event": "points_redeemed",
"tenant_id": "5927c0df-0284-4f27-ba49-6b1264b788b4",
"user_id": "1bebdfc0-2f3f-4233-a66c-706e8cb41060",
"reference_id": "inv_99850",
"points": 1000,
"timestamp": "2026-07-25T12:00:00Z",
"signature": "a1b2c3d4e5f6..."
}Verify webhooks by computing HMAC-SHA256 over the JSON body (excluding the signature field) using your webhook secret.
// Node.js
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const payload = { event: body.event, tenant_id: body.tenant_id,
user_id: body.user_id, reference_id: body.reference_id,
points: body.points, timestamp: body.timestamp };
const expected = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature), Buffer.from(expected)
);
}// PHP
function verifyWebhook($body, $signature, $secret) {
$payload = json_encode([
'event' => $body['event'],
'tenant_id' => $body['tenant_id'],
'user_id' => $body['user_id'],
'reference_id' => $body['reference_id'],
'points' => $body['points'],
'timestamp' => $body['timestamp'],
]);
return hash_equals(
hash_hmac('sha256', $payload, $secret),
$signature
);
}All errors follow a consistent format: { "status": "error", "code": "ERROR_CODE", "message": "Human-readable description" }
| HTTP | Code | Description |
|---|---|---|
400 | INVALID_REQUEST | Missing or invalid request fields |
400 | INSUFFICIENT_BALANCE | Customer doesn't have enough points for this redemption |
400 | ZERO_POINTS | No points calculated — check category names and multipliers |
400 | WEAK_PASSWORD | Password must be at least 6 characters |
401 | MISSING_API_KEY | X-PingBacks-API-Key header is missing |
401 | INVALID_API_KEY | API key is invalid or tenant is suspended |
401 | UNAUTHORIZED | JWT Bearer token missing or invalid |
401 | INVALID_CREDENTIALS | Wrong email or password |
403 | FORBIDDEN | Insufficient permissions for this endpoint |
404 | USER_NOT_FOUND | No user found with that email or Ping-ID |
409 | DUPLICATE_INVOICE | This invoice_id has already been processed |
409 | EMAIL_EXISTS | This email is already registered |
500 | INTERNAL_ERROR | Unexpected server error — contact support |
Minimal, zero-dependency client for PHP 7.4+. Works with WHMCS, WordPress, WooCommerce, and any custom CMS.
<?php
require_once 'PingBacksClient.php';
$client = new PingBacksClient('pb_live_8f391a...', 'https://api.pingbacks.io');
// 1. Credit points after payment
$result = $client->earn(
pingId: 'PB-A3F8K2M9X',
tenantCustomerId: 'cust_12345',
invoiceId: 'inv_99812',
items: [
['category' => 'hosting', 'amount_eur' => 49.90],
['category' => 'domain', 'amount_eur' => 14.90],
]
);
echo "Earned: {$result['points_earned']} points\n";
// 2. Check balance
$balance = $client->getBalance(pingId: 'PB-A3F8K2M9X');
echo "Balance: {$balance['global_balance']} points\n";
// 3. Redeem points
$redeem = $client->redeemInvoice(
pingId: 'PB-A3F8K2M9X',
pointsToRedeem: 500,
invoiceId: 'inv_789'
);
echo "Redeemed: {$redeem['points_redeemed']}\n";
echo "Remaining: {$redeem['remaining_global_balance']}\n";
// 4. Provide your own voucher codes for the rewards shop
$import = $client->importVoucherCodes(
poolId: 'pool-uuid-here',
codes: ['SUMMER-001', 'SUMMER-002', 'SUMMER-003']
);
echo "Imported: {$import['imported']} codes, {$import['duplicates_skipped']} skipped\n";
// 5. List sold codes for reconciliation with your billing system
$sold = $client->getSoldVoucherCodes(poolId: 'pool-uuid-here');
foreach ($sold['codes'] as $code) {
echo "{$code['code']} - {$code['status']}\n";
}Full SDK source and example script: github.com/Host-On/pingbacks/sdk/php
Import our OpenAPI 3.0 spec into Postman, Swagger, or Insomnia to quickly test endpoints and generate request wrappers.