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.
Integration 02
Inline integration
Inline integration allows you to keep your customer on your website while the secure BSTPay checkout opens inside an overlay. The actual payment interface remains hosted by BSTPay.
Pay without leaving your website
Your backend creates the checkout and your frontend opens the secure checkout inside a BSTPay payment modal.
Your Website
│
│ Your backend creates checkout
▼
BSTPay API
│
│ checkout_url / token
▼
BSTPay JavaScript SDK
│
│ opens secure iframe
▼
┌──────────────────────────────┐
│ BSTPay Checkout │
│ │
│ Bank Transfer │
│ Card │
│ Mobile Money │
│ BSTPay ID │
│ │
└──────────────────────────────┘
│
│ payment completed
▼
postMessage event
│
▼
Your Website
│
▼
Webhook confirmation
Do not put your secret key in JavaScript
Your server must create the checkout. The browser receives only the checkout URL/token required to open that specific transaction.
Integration 01
Standard integration
Standard integration redirects your customer from your website to the secure BSTPay hosted checkout page. This is the simplest and recommended integration for most merchants.
1. Create checkout
Your backend sends the payment information to BSTPay using your secret API key.
2. Receive checkout URL
BSTPay returns a unique checkout URL for the transaction.
3. Redirect customer
Redirect the customer to BSTPay to complete payment.
Recommended
PHP server integration
<?php
$apiUrl =
'https://checkout.bstpays.com/v1/checkout.php';
$apiKey =
'bst_live_YOUR_SECRET_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
],
CURLOPT_TIMEOUT =>
30
]);
$response =
curl_exec($ch);
$httpCode =
curl_getinfo(
$ch,
CURLINFO_HTTP_CODE
);
$curlError =
curl_error($ch);
curl_close($ch);
if ($response === false) {
die(
'BSTPay connection failed: '
. $curlError
);
}
$result =
json_decode(
$response,
true
);
if (
$httpCode >= 200
&&
$httpCode < 300
&&
($result['status'] ?? '')
=== 'success'
&&
!empty(
$result['data']['checkout_url']
)
) {
header(
'Location: '
. $result['data']['checkout_url']
);
exit;
}
die(
$result['message']
??
'Unable to create BSTPay checkout.'
);
Secret key stays on your server
Never put the BSTPay secret API key in browser JavaScript. The browser should only receive the checkout URL or checkout token generated by your backend.
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 an eligible BSTPay account can authorize a payment through BSTPay, subject to the available payment method, currency, account status and applicable transaction limits.
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
Production checklist
Inline SDK
Load the BSTPay JavaScript SDK on your payment page and provide it with the checkout URL returned by your server.
1. Load the SDK
<script
src="https://checkout.bstpays.com/js/bstpay.js">
</script>
2. Create the checkout on your server
Your backend should call the normal BSTPay checkout API. Never call the API using your secret key directly from browser JavaScript.
3. Open the checkout
<button
type="button"
onclick="startBSTPay()"
class="px-6 py-3 rounded-xl bg-blue-600 text-white font-bold">
Pay with BSTPay
</button>
<script>
function startBSTPay()
{
BSTPay.open({
checkoutUrl:
'<?php echo $checkoutUrl; ?>',
onClose:
function () {
console.log(
'BSTPay checkout closed'
);
}
});
}
</script>
Payment success
window.BSTPayOnSuccess =
function (payment) {
console.log(
'Payment successful:',
payment
);
/*
* Do not rely only on this
* browser event to fulfil
* the order.
*
* Confirm the payment on
* your backend using the
* BSTPay webhook or status API.
*/
window.location.href =
'/payment-success.php';
};
Recommended
Use the inline event for the customer interface, but use the BSTPay webhook or server-side status API as the authoritative payment confirmation.