Accept payments with BSTPay
Integrate BSTPay into your website and let your customers pay through bank transfer, mobile money, card, or BSTPay ID using a secure hosted checkout.
Simple API
Create a checkout with one API request.
Secure
Payment confirmation is server-to-server.
Multiple Methods
Give customers multiple ways to pay.
Overview
How the integration works
Your Website
│
│ POST /v1/checkout.php
▼
BSTPay API
│
│ returns checkout_url
▼
BSTPay Hosted Checkout
│
├── Bank Transfer
├── Mobile Money
├── Card
└── BSTPay ID
│
▼
Payment Provider
│
▼
BSTPay Webhook Processing
│
├── Validate payment
├── Update transaction
├── Settle merchant
└── Send merchant webhook
│
▼
Your Website
Your website does not need direct access to BSTPay's payment-provider credentials. BSTPay handles the payment infrastructure and sends your website a normalized payment notification.
Step 1
API credentials
Your BSTPay API key authenticates requests made from your server. Never expose the API key in frontend JavaScript, HTML, mobile applications, or public repositories.
Keep your API key private
API requests should be made from your backend server.
Authorization
Authorization: Bearer bst_live_YOUR_API_KEY
Step 2
Create a checkout
When your customer is ready to pay, your backend sends a request to BSTPay.
https://checkout.bstpays.com/v1/checkout.php
Request
{
"amount": 25000,
"currency": "NGN",
"merchant_order_reference": "ORDER-100025",
"description": "Payment for Order #100025",
"customer": {
"name": "John Doe",
"email": "customer@example.com",
"phone": "08012345678"
},
"redirect_url":
"https://example.com/payment-complete.php",
"metadata": {
"order_id": "100025"
}
}
PHP example
<?php
$apiUrl =
'https://checkout.bstpays.com/v1/checkout.php';
$apiKey =
'bst_live_YOUR_API_KEY';
$payload = [
'amount' => 25000,
'currency' => 'NGN',
'merchant_order_reference' =>
'ORDER-100025',
'description' =>
'Payment for Order #100025',
'customer' => [
'name' =>
'John Doe',
'email' =>
'customer@example.com',
'phone' =>
'08012345678'
],
'redirect_url' =>
'https://example.com/payment-complete.php',
'metadata' => [
'order_id' =>
'100025'
]
];
$ch = curl_init($apiUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS =>
json_encode($payload),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'Authorization: Bearer ' . $apiKey
]
]);
$response = curl_exec($ch);
$httpCode =
curl_getinfo(
$ch,
CURLINFO_HTTP_CODE
);
curl_close($ch);
$result =
json_decode(
$response,
true
);
if (
$httpCode >= 200
&&
$httpCode < 300
&&
isset(
$result['data']['checkout_url']
)
) {
header(
'Location: '
. $result['data']['checkout_url']
);
exit;
}
die(
$result['message']
?? 'Unable to create payment.'
);
Checkout response
BSTPay returns a secure checkout URL. Redirect your customer to this URL.
{
"status": "success",
"message": "Checkout created successfully.",
"data": {
"checkout_reference":
"BSTCHK-20260912180200-A12B34CD",
"merchant_order_reference":
"ORDER-100025",
"amount": "25000.00",
"currency": "NGN",
"checkout_url":
"https://checkout.bstpays.com/checkout.php?token=BSTCHK_...",
"status": "pending"
}
}
Redirect the customer
Never create your own payment form for this integration unless you are using BSTPay's API directly. The hosted checkout handles the customer payment experience.
Hosted checkout
The checkout URL opens the BSTPay payment page. Your customer can select their preferred payment method.
Example
Choose payment method
Bank Transfer
Mobile Money
Card
BSTPay ID
Payment methods
Bank Transfer
BSTPay generates a temporary payment account for the checkout. The customer transfers the exact payment amount into that account.
Mobile Money
Customers can use a supported mobile-money payment flow where available for the checkout currency.
Card
Customers can pay using supported debit or credit cards through the configured payment provider.
BSTPay ID
Customers with a BSTPay account can authorize a payment from their BSTPay balance.
Redirect handling
After payment, BSTPay can redirect the customer to the URL supplied when creating the checkout.
Important
Do not mark an order as paid solely because the customer reached your redirect URL. The redirect is a customer experience feature. Your server should rely on the BSTPay webhook or a verified status request to confirm payment.
Check payment status
You can query a checkout when you need to verify its current state.
/v1/checkout-status.php
GET
https://checkout.bstpays.com/v1/checkout-status.php?token=CHECKOUT_TOKEN
Response
{
"status": "success",
"data": {
"checkout_reference":
"BSTCHK-20260912180200-A12B34CD",
"merchant_order_reference":
"ORDER-100025",
"amount": "25000.00",
"currency": "NGN",
"payment_method":
"bank_transfer",
"status":
"successful",
"amount_received":
"25000.00",
"provider_reference":
"FINCRA_REFERENCE",
"paid_at":
"2026-09-12 18:10:23"
}
}
Server-to-server
Webhooks
Webhooks are the recommended way to know when a payment has actually been completed.
Customer pays
The customer completes payment.
BSTPay confirms
BSTPay verifies the provider notification.
Your server receives event
Your order can now be marked paid.
Webhook payload
A successful payment notification looks like this:
{
"event": "payment.successful",
"data": {
"checkout_reference":
"BSTCHK-20260912180200-A12B34CD",
"merchant_id":
"BSTMERCHANT001",
"merchant_order_reference":
"ORDER-100025",
"amount": 25000,
"amount_received": 25000,
"currency": "NGN",
"payment_method":
"bank_transfer",
"status": "successful",
"provider_reference":
"FINCRA_REFERENCE",
"customer": {
"name": "John Doe",
"email":
"customer@example.com",
"phone":
"08012345678"
},
"paid_at":
"2026-09-12 18:10:23"
}
}
Verify the webhook signature
Every webhook request contains an
X-BSTPay-Signature
header.
<?php
$payload =
file_get_contents('php://input');
$signature =
$_SERVER['HTTP_X_BSTPAY_SIGNATURE']
?? '';
$webhookSecret =
'YOUR_WEBHOOK_SECRET';
$expected =
hash_hmac(
'sha256',
$payload,
$webhookSecret
);
if (
!hash_equals(
$expected,
$signature
)
) {
http_response_code(401);
exit('Invalid signature');
}
$data =
json_decode(
$payload,
true
);
if (
($data['event'] ?? '')
=== 'payment.successful'
) {
$payment =
$data['data'];
$orderReference =
$payment[
'merchant_order_reference'
];
/*
| Mark the order as paid here.
*/
}
http_response_code(200);
echo json_encode([
'status' => 'received'
]);
Complete webhook example
Create an endpoint on your website such as:
/api/bstpay-webhook.php
<?php
$payload =
file_get_contents('php://input');
$signature =
$_SERVER['HTTP_X_BSTPAY_SIGNATURE']
?? '';
$secret =
'YOUR_WEBHOOK_SECRET';
$expected =
hash_hmac(
'sha256',
$payload,
$secret
);
if (
!hash_equals(
$expected,
$signature
)
) {
http_response_code(401);
exit('Invalid signature');
}
$data =
json_decode(
$payload,
true
);
if (!is_array($data)) {
http_response_code(400);
exit('Invalid payload');
}
if (
($data['event'] ?? '')
!== 'payment.successful'
) {
http_response_code(200);
exit('Event ignored');
}
$payment =
$data['data'];
$orderReference =
$payment[
'merchant_order_reference'
];
$amount =
$payment['amount'];
$currency =
$payment['currency'];
$status =
$payment['status'];
/*
|--------------------------------------------------------------------------
| Verify payment
|--------------------------------------------------------------------------
*/
if ($status !== 'successful') {
http_response_code(200);
exit('Payment not successful');
}
/*
|--------------------------------------------------------------------------
| IMPORTANT
|--------------------------------------------------------------------------
|
| Look up your order using $orderReference.
| Do not trust the amount alone.
|
*/
/*
|--------------------------------------------------------------------------
| Example:
|--------------------------------------------------------------------------
|
| UPDATE orders
| SET payment_status = 'paid'
| WHERE order_reference = ?
|
*/
http_response_code(200);
echo json_encode([
'status' => 'received'
]);
Security requirements
Keep API keys on your server
Never place a secret API key inside frontend JavaScript.
Verify webhook signatures
Always verify X-BSTPay-Signature before processing a payment notification.
Use order references
Match the webhook's merchant_order_reference against an order in your own database.
Make webhook processing idempotent
The same notification may be delivered more than once. Your order should only be marked paid once.
Use HTTPS
Your redirect URL and webhook endpoint should use HTTPS.
Testing your integration
Before going live, test the complete lifecycle.
| Test | Expected Result |
|---|---|
| Create checkout | BSTPay returns checkout_url. |
| Open checkout | Customer sees available payment methods. |
| Make payment | Payment provider confirms payment. |
| Receive webhook | Your endpoint receives payment.successful. |
| Verify signature | Signature matches your webhook secret. |
| Mark order paid | Your order is updated once. |
Before going live