Payments
The Payments API lets you initiate, query, and refund payments across all supported providers. POPFAB handles routing, failover, and status normalization automatically.
Endpoints
POST
/v1/paymentsGET
/v1/paymentsGET
/v1/payments/:idPOST
/v1/payments/:id/syncPOST
/v1/payments/:id/refundInitiate a Payment
POST
/v1/paymentsCreates a new payment and routes it to the best available provider.
Request headers
| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | string | Required | Bearer YOUR_API_KEY |
Idempotency-Key | string | Required | A unique key per payment attempt (UUID or your order ID). Prevents duplicate charges if the request is retried. |
Content-Type | string | Required | Must be application/json |
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Required | Amount in the smallest currency unit (kobo for NGN, pesewas for GHS, etc.). Must be a positive integer. |
currency | string | Required | ISO 4217 currency code: NGN, GHS, KES, ZAR, UGX, XOF, USD. |
payment_method | string | Required | One of: card, bank_transfer, ussd, mobile_money, qr. |
reference | string | Required | Your unique payment reference. Alphanumeric, hyphens, and underscores only (a–z, A–Z, 0–9, -, _). Max 255 characters. Must be unique per merchant. |
customer | object | Required | Customer object. Must include email. Optionally includes name and phone. |
customer.email | string | Required | Customer's email address. |
customer.name | string | Optional | Customer's full name. |
customer.phone | string | Optional | Customer's phone number. |
routing_override | string | Optional | Force a specific provider, bypassing routing rules: paystack, flutterwave, monnify, squad, interswitch, payaza. |
callback_url | string | Optional | Absolute URL to return the customer to after a redirect-based flow. Use HTTPS in production. |
metadata | object | Optional | Up to 20 key-value pairs of string:string. Stored on the payment and returned in webhook events. |
Example requestbash
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_abc123_v1" \
-d '{
"amount": 150000,
"currency": "NGN",
"payment_method": "card",
"reference": "MYAPP-ORDER-7890",
"customer": {
"email": "ada@example.com",
"name": "Ada Okafor",
"phone": "+2348012345678"
},
"metadata": {
"order_id": "7890",
"plan": "premium"
}
}'200 OK — Payment objectjson
{
"id": "ppfb_pay_01HX9T2KBQM4Z3YWN5E6R7VP8S",
"merchant_id": "ppfb_merch_01HX8W7K4YR6E9N2M3Q5T1ABCD",
"idempotency_key": "order_abc123_v1",
"reference": "MYAPP-ORDER-7890",
"amount": 150000,
"currency": "NGN",
"payment_method": "card",
"status": "pending",
"provider": "paystack",
"provider_reference": "psk_T8x29kLMqpn",
"checkout_url": "https://checkout.paystack.com/abc123",
"customer": {
"email": "ada@example.com",
"name": "Ada Okafor",
"phone": "+2348012345678"
},
"metadata": { "order_id": "7890", "plan": "premium" },
"fees": {
"popfabFee": 225,
"providerFee": 375,
"totalFee": 600
},
"routing_context": {
"strategy": "cost_optimizer",
"providersConsidered": ["paystack", "flutterwave"],
"selectedProvider": "paystack",
"selectionReason": "lowest_cost",
"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"
}Payment response fields
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The POPFAB payment ID. Use this ID to retrieve, synchronize, or refund the payment. |
merchant_id | string | Required | The POPFAB merchant ID that owns the payment. |
idempotency_key | string | Required | The idempotency key supplied when the payment was initiated. |
reference | string | Required | The unique merchant reference supplied in the request. |
amount | integer | Required | Payment amount in the currency's smallest unit. |
currency | string | Required | ISO 4217 currency code. |
payment_method | string | Required | Payment method selected for the transaction. |
status | string | Required | Current normalized payment status. |
provider | string | null | Optional | Provider selected by POPFAB. It can be null before routing completes. |
provider_reference | string | null | Optional | The payment reference assigned by the selected provider. |
checkout_url | string | null | Optional | Hosted authorization URL. When present, redirect the customer here to complete payment. |
customer | object | Required | Customer details supplied when the payment was initiated. |
metadata | object | null | Optional | Merchant metadata supplied in the request. |
fees | object | null | Optional | Fee breakdown when available. |
routing_context | object | null | Optional | Provider-routing and failover information when routing has completed. |
failure_reason | string | null | Optional | Normalized failure reason when the payment fails. |
created_at | string | Required | ISO 8601 creation timestamp. |
updated_at | string | Required | ISO 8601 timestamp of the latest update. |
ℹ
checkout_url is conditional. Hosted card and redirect flows normally return one, while methods such as bank transfer or USSD may instead rely on method-specific instructions. Redirect the customer only when the field is present. A browser redirect is not proof of payment; confirm the final status using a webhook or by retrieving the payment.List Payments
GET
/v1/paymentsReturns a cursor-paginated list of payments for your merchant account, newest first.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | Optional | Filter by status: pending, processing, success, failed, reversed, expired. |
provider | string | Optional | Filter by the selected provider, for example paystack or flutterwave. |
limit | integer | Optional | Number of results per page. Default 25, max 100. |
cursor | string | Optional | Pagination cursor from a previous response next_cursor field. Treat it as an opaque value. |
List successful paymentsbash
curl "https://api.popfab.io/v1/payments?status=success&limit=50" \
-H "Authorization: Bearer sk_test_YOUR_API_KEY"Responsejson
{
"data": [
{ "id": "ppfb_pay_...", "status": "success", ... },
{ "id": "ppfb_pay_...", "status": "success", ... }
],
"next_cursor": "eyJpZCI6InBwZmJfcGF5XyJ9",
"has_more": true
}Get a Payment
GET
/v1/payments/:idRetrieves the current state of a payment by its POPFAB ID or your merchant reference.
Get payment by IDbash
curl https://api.popfab.io/v1/payments/ppfb_pay_01HX9T2KBQM4Z3YWN5E6R7VP8S \
-H "Authorization: Bearer sk_test_YOUR_API_KEY"Synchronize Payment Status
POST
/v1/payments/:id/syncQueries the selected provider and synchronizes the payment status.
| Parameter | Type | Required | Description |
|---|---|---|---|
force | boolean | Optional | Set to true to recheck a failed or expired payment. Successful and reversed payments are never re-queried. |
Synchronize a pending paymentbash
curl -X POST https://api.popfab.io/v1/payments/ppfb_pay_01HX9T2KBQM4Z3YWN5E6R7VP8S/sync \
-H "Authorization: Bearer sk_test_YOUR_API_KEY"ℹ
Normal integrations should use webhooks and
GET /v1/payments/:id. Use this endpoint for explicit reconciliation when you need an immediate provider check. The response includes asynced boolean and may include a reason when no update was made.Refund a Payment
POST
/v1/payments/:id/refundInitiates a full or partial refund for a payment with status success.
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Optional | Amount to refund in the smallest currency unit. Omit for a full refund. |
reason | string | Optional | Reason for the refund. Max 500 characters. Stored for audit purposes. |
Partial refund of ₦500 (50000 kobo)bash
curl -X POST https://api.popfab.io/v1/payments/ppfb_pay_01HX9T2K/refund \
-H "Authorization: Bearer sk_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"reason": "Customer request — partial return"
}'Payment Statuses
| Status | Description |
|---|---|
| pending | Request received. Awaiting routing and provider processing. |
| processing | Routed to a provider. Awaiting confirmation from the provider. |
| success | Payment confirmed by the provider. Value delivered. |
| failed | Payment was declined or could not be completed by any provider. |
| reversed | A refund or reversal has been successfully processed. |
| expired | The provider authorization or payment window expired before completion. |
ℹ
payment.pending_confirmation is a webhook event emitted while a provider confirmation is outstanding. It is not a value returned in the payment object's status field.Idempotency
The Idempotency-Key header is required on all POST /v1/payments requests. It ensures that retrying a failed network request does not result in a duplicate charge.
ℹ
If you send a second request with the same
Idempotency-Key, POPFAB returns the original payment object without creating a new one. Keys expire after 24 hours. If you receive a 409 IDEMPOTENCY_CONFLICT, the key was used with a different request body — generate a new key.