Quick Start
Make your first payment in under 5 minutes using the POPFAB API.
1Create an account
Sign up at popfab.io/signup to get your merchant account. Once registered, navigate to API Keys in the dashboard to generate a test key.
sk_test_. No real money moves in sandbox — all provider responses are simulated.2Initiate a payment
Send a POST /v1/payments request with your API key in the Authorization header. Always include a unique Idempotency-Key to prevent duplicate charges.
curl -X POST https://api.popfab.io/v1/payments \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order_12345_attempt_1" \
-d '{
"amount": 50000,
"currency": "NGN",
"payment_method": "card",
"reference": "ORD-12345",
"customer": {
"email": "john@example.com",
"name": "John Doe"
},
"metadata": {
"order_id": "ORD-12345"
}
}'const response = await fetch('https://api.popfab.io/v1/payments', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_test_YOUR_API_KEY',
'Content-Type': 'application/json',
'Idempotency-Key': 'order_12345_attempt_1',
},
body: JSON.stringify({
amount: 50000, // in kobo (₦500.00)
currency: 'NGN',
payment_method: 'card',
reference: 'ORD-12345',
customer: {
email: 'john@example.com',
name: 'John Doe',
},
metadata: {
order_id: 'ORD-12345',
},
}),
});
const payment = await response.json();
if (payment.checkout_url) {
// Send this URL to your frontend and redirect the customer there.
console.log('Redirect customer to:', payment.checkout_url);
}3Handle the response
A successful request returns a payment object. The initial status is usually pending or processing. Listen for a webhook event to know the final outcome.
{
"id": "ppfb_pay_01HX9T2KBQM4Z3YWN5E6R7VP8S",
"merchant_id": "ppfb_merch_01HX8W7K4YR6E9N2M3Q5T1ABCD",
"idempotency_key": "order_12345_attempt_1",
"reference": "ORD-12345",
"amount": 50000,
"currency": "NGN",
"payment_method": "card",
"status": "pending",
"provider": "paystack",
"provider_reference": "psk_T8x29kLMqpn",
"checkout_url": "https://checkout.paystack.com/abc123",
"customer": {
"email": "john@example.com",
"name": "John Doe"
},
"metadata": { "order_id": "ORD-12345" },
"fees": {
"popfabFee": 75,
"providerFee": 125,
"totalFee": 200
},
"routing_context": {
"strategy": "success_rate",
"providersConsidered": ["paystack", "flutterwave"],
"selectedProvider": "paystack",
"selectionReason": "highest_success_rate",
"attempts": [
{
"provider": "paystack",
"attemptedAt": "2025-03-19T10:23:45.000Z",
"outcome": "success",
"latencyMs": 284
}
]
},
"failure_reason": null,
"created_at": "2025-03-19T10:23:45.000Z",
"updated_at": "2025-03-19T10:23:45.000Z"
}checkout_url when it is present. It is conditional because not every payment method uses a hosted checkout page. Confirm the final result using webhooks orGET /v1/payments/:id; do not treat the customer's browser redirect as proof of payment.4Set up a webhook
Register a webhook endpoint to receive real-time payment status updates. POPFAB delivers signed events with at-least-once guarantees and automatic retries.
curl -X POST https://api.popfab.io/v1/webhooks/endpoints \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/popfab",
"events": ["payment.success", "payment.failed"],
"enabled": true
}'import crypto from 'crypto';
export async function POST(req) {
const body = await req.text();
const signature = req.headers.get('X-POPFAB-Signature');
const webhookSecret = process.env.POPFAB_WEBHOOK_SECRET;
// Verify signature
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(body)
.digest('hex');
if (signature !== `sha256=${expected}`) {
return new Response('Unauthorized', { status: 401 });
}
const event = JSON.parse(body);
if (event.event === 'payment.success') {
const payment = event.data;
// Fulfill the order
await fulfillOrder(payment.metadata.order_id);
}
return new Response('OK', { status: 200 });
}5Go live
When you're ready to accept real payments, generate a live API key (sk_live_...) from the dashboard. No code changes needed — just swap the key.