API Reference
Everything you need to integrate PingBacks into your hosting platform. Three core endpoints, JWT auth, HMAC-signed webhooks.
Base URL
https://api.pingbacks.io
All endpoints return JSON. Use Content-Type: application/json for POST/PUT requests.
Authentication
PingBacks supports two authentication methods — API Keys for server-to-server integration and JWT Bearer Tokens for user-facing dashboards.
1 API Key Authentication
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 or version control.
2 JWT Bearer Token
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...
Core Concept: Ping-ID
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.
✓ With Ping-ID
// Customer enters Ping-ID at checkout
POST /api/v1/earn
{ "ping_id": "PB-A3F8K2M9X", ... }Also Supported: Email
// Fallback for legacy integrations
POST /api/v1/earn
{ "customer_email": "kunde@example.de", ... }Earning Points
/api/v1/earnCredit points to a customer after a successful payment. Idempotent — sending the same invoice_id twice returns a 409 Conflict.
Request Body
| 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.
Example Request
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 }
]
}'Example Response 200 OK
{
"status": "success",
"pingbacks_user_id": "8040dd4c-6929-4741-8fd6-69386c308d2f",
"points_earned": 648,
"new_global_balance": 12850
}Multiplier Calculation
Points are calculated as: floor(amount_eur × multiplier). Each provider configures their own multipliers per category. Example with multiplier 10: €14.90 → 149 points.
Query Balance
/api/v1/balanceLook up a customer's current point balance. Use this to display points in your customer panel.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | * | Customer's email address |
ping_id | string | * | Customer's Ping-ID (alternative) |
Example Request
curl "https://api.pingbacks.io/api/v1/balance?ping_id=PB-A3F8K2M9X" \ -H "X-PingBacks-API-Key: pb_live_8f391a..."
Example Response 200 OK
{
"customer_email": "developer@agency-xyz.de",
"ping_id": "PB-A3F8K2M9X",
"global_balance": 12850,
"status": "linked"
}Status linked means the customer exists. not_found means no account with that email/Ping-ID.
Redeeming Points
/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.
Request Body
| 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 |
Example Request
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"
}'Example Response 200 OK
{
"status": "success",
"points_redeemed": 1000,
"equivalent_value_eur": 10.00,
"remaining_global_balance": 11850
}1 PingBack = €0.01. Redemption is atomic — either fully succeeds or fully fails. If the customer has insufficient points, returns 400 INSUFFICIENT_BALANCE.
Webhooks
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.
Webhook Payload
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..."
}Signature Verification
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
);
}Auth API
JWT-based authentication for provider dashboards and customer portals. All auth endpoints are public (no API key required).
/api/auth/register/tenantRegister a new provider. Goes into pending approval state.
// Request
{
"company_name": "ServerBlitz GmbH",
"contact_email": "kontakt@serverblitz.de",
"contact_name": "Max Mustermann",
"admin_email": "admin@serverblitz.de",
"admin_password": "secure1234",
"webhook_url": "https://serverblitz.de/webhooks/pingbacks"
}
// Response 201 Created
{
"status": "success",
"message": "Registration submitted. Awaiting admin approval.",
"tenant_id": "5927c0df-..."
}/api/auth/register/userRegister a new end customer. Returns JWT token immediately — no approval needed.
// Request
{ "email": "developer@agency-xyz.de", "password": "secure1234" }
// Response 201 Created
{
"status": "success",
"token": "eyJhbGciOi...",
"user": {
"id": "1bebdfc0-...",
"email": "developer@agency-xyz.de",
"current_balance": 0,
"ping_id": "PB-A3F8K2M9X"
}
}/api/auth/login/tenantLogin as a provider. Returns JWT token with tenant context.
// Response 200 OK
{
"status": "success",
"token": "eyJhbGciOi...",
"user": {
"email": "admin@serverblitz.de",
"tenantId": "5927c0df-...",
"tenantName": "ServerBlitz GmbH",
"role": "admin"
}
}/api/auth/login/userLogin as an end customer. Returns JWT token with wallet context.
// Response 200 OK
{
"status": "success",
"token": "eyJhbGciOi...",
"user": {
"email": "developer@agency-xyz.de",
"current_balance": 12850,
"ping_id": "PB-A3F8K2M9X"
}
}Dashboard API JWT Required
Authenticated endpoints for provider dashboards. All require Authorization: Bearer <token>.
GET /api/auth/tenant/stats
Returns provider info, transaction counts, 30-day points total, unique customer count, and current multipliers.
GET /api/auth/tenant/transactions?limit=100
Paginated transaction list for the authenticated provider. Includes customer email, points before/after, timestamp.
PUT /api/auth/tenant/multipliers
Update multipliers. Sends full replacement array. Body: { "multipliers": [{"category":"hosting","points_per_euro":10}] }
GET /api/auth/admin/registrations
List all provider registrations with status. For admin users approving new providers.
POST /api/auth/admin/approve
Approve or reject a provider registration. Body: { "tenant_id": "...", "approved": true }. Returns generated API key on approval.
GET /api/auth/user/transactions
End-customer transaction history with provider names. Returns current balance and Ping-ID.
Error Codes
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 |
PHP SDK
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";Full SDK source and example script: github.com/Host-On/pingbacks/sdk/php
OpenAPI Specification
Import our OpenAPI 3.0 spec into Postman, Swagger, or Insomnia.
Download openapi.yaml