Secure payment integration for custom websites, apps, and WooCommerce stores.
SecureNexPay lets merchants create secure payment links, redirect customers to checkout, receive signed payment webhooks, and mark orders as paid safely.
Create PaymentSecure CheckoutAllowed DomainHMAC SignatureTimestampNonce Replay ProtectionWebhook VerificationWebhook RetryWooCommerce Ready1. Get Public Key and Secret Key from SecureNexPay Merchant Panel 2. Create payment from your backend/server 3. Generate HMAC signature using Secret Key 4. Redirect customer to checkout_url 5. Receive signed webhook 6. Verify webhook signature 7. Mark order as paid
https://merchant.securenexpay.com
| File | Required | Purpose |
|---|---|---|
config.php | Yes | Store Public Key, Secret Key, API URLs. This file must not be public. |
create-payment.php | Yes | Create payment request, sign request, call SecureNexPay API, redirect customer. |
webhook.php | Yes | Receive payment notification, verify signature, update order status. |
success.php | Optional | Show customer a success/thank-you page after payment. |
cancel.php | Optional | Show customer a failed/cancelled payment page. |
Customer clicks Pay Now ↓ Merchant backend creates signed request ↓ POST https://merchant.securenexpay.com/api/create-payment.php ↓ SecureNexPay validates: Public Key + Merchant Status + HMAC Signature + Timestamp + Nonce + Allowed Domain ↓ Payment Link Created ↓ Customer redirects to checkout_url ↓ Customer completes payment ↓ SecureNexPay sends signed webhook to merchant webhook_url ↓ Merchant verifies webhook signature ↓ Order marked as paid
POST https://merchant.securenexpay.com/api/create-payment.php
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | Use application/json. |
| Accept | Recommended | Use application/json. |
| X-SecureNexPay-Timestamp | Yes | Current Unix timestamp. Request must be fresh. |
| X-SecureNexPay-Nonce | Yes | Random unique string for every request. Prevents replay attack. |
| X-SecureNexPay-Signature | Yes | HMAC SHA256 signature generated using Secret Key. |
{
"public_key": "pk_live_xxxxxxxxxxxxxxxxx",
"order_id": "ORDER1001",
"amount": "190.00",
"customer_name": "John Doe",
"customer_email": "john@example.com",
"customer_phone": "01700000000",
"success_url": "https://yourdomain.com/payment-success",
"cancel_url": "https://yourdomain.com/payment-cancel",
"webhook_url": "https://yourdomain.com/api/securenexpay-webhook"
}
signature = HMAC_SHA256(raw_json_body + timestamp + nonce, secret_key)
| Field | Required | Description |
|---|---|---|
| public_key | Yes | Merchant public key. |
| order_id | Yes | Your website/app order ID. |
| amount | Yes | Payment amount. Example: 190.00 |
| customer_name | No | Customer name. |
| customer_email | No | Customer email. |
| customer_phone | No | Customer phone number. |
| success_url | Yes if allowed domain is set | Customer redirect URL after success. Domain must match allowed domain. |
| cancel_url | Yes if allowed domain is set | Customer redirect URL after cancel/fail. Domain must match allowed domain. |
| webhook_url | Yes if allowed domain is set | Server webhook endpoint. Domain must match allowed domain. |
<?php
define('SNP_PUBLIC_KEY', 'pk_live_xxxxxxxxxxxxxxxxx');
define('SNP_SECRET_KEY', 'sk_live_xxxxxxxxxxxxxxxxx');
define('SNP_CREATE_URL', 'https://merchant.securenexpay.com/api/create-payment.php');
<?php
require_once __DIR__ . '/config.php';
$orderId = 'ORDER1001';
$amount = '190.00';
$payload = [
'public_key' => SNP_PUBLIC_KEY,
'order_id' => $orderId,
'amount' => $amount,
'customer_name' => 'John Doe',
'customer_email' => 'john@example.com',
'customer_phone' => '01700000000',
'success_url' => 'https://yourdomain.com/success.php?order_id=' . urlencode($orderId),
'cancel_url' => 'https://yourdomain.com/cancel.php?order_id=' . urlencode($orderId),
'webhook_url' => 'https://yourdomain.com/webhook.php'
];
$rawBody = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$timestamp = time();
$nonce = bin2hex(random_bytes(16));
$signature = hash_hmac('sha256', $rawBody . $timestamp . $nonce, SNP_SECRET_KEY);
$ch = curl_init(SNP_CREATE_URL);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $rawBody,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
'X-SecureNexPay-Timestamp: ' . $timestamp,
'X-SecureNexPay-Nonce: ' . $nonce,
'X-SecureNexPay-Signature: ' . $signature
],
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$result = json_decode($response, true);
if ($httpCode >= 200 && $httpCode < 300 && !empty($result['checkout_url'])) {
header('Location: ' . $result['checkout_url']);
exit;
}
echo 'Payment creation failed.';
echo '<pre>' . htmlspecialchars($response) . '</pre>';
<?php
require_once __DIR__ . '/config.php';
header('Content-Type: application/json');
$rawPayload = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_SECURENEXPAY_SIGNATURE'] ?? '';
$expectedSignature = hash_hmac('sha256', $rawPayload, SNP_SECRET_KEY);
if (!$receivedSignature || !hash_equals($expectedSignature, $receivedSignature)) {
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Invalid webhook signature.']);
exit;
}
$data = json_decode($rawPayload, true);
if (!is_array($data)) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Invalid JSON payload.']);
exit;
}
if (($data['status'] ?? '') === 'COMPLETED') {
$orderId = $data['order_id'];
$paymentUid = $data['payment_uid'];
$transactionId = $data['transaction_id'];
$amount = $data['amount'];
// TODO:
// 1. Find order by $orderId
// 2. Verify amount matches your order amount
// 3. Store $paymentUid and $transactionId
// 4. Mark order as paid/completed
}
http_response_code(200);
echo json_encode(['success' => true, 'message' => 'Webhook processed.']);
<?php echo 'Payment successful. Your order is being processed.';
<?php echo 'Payment cancelled or failed. Please try again.';
{
"success": true,
"message": "Payment created successfully.",
"payment_uid": "PAY20260614123456xxxx",
"provider_payment_uid": null,
"order_id": "ORDER1001",
"amount": "190.00",
"checkout_url": "https://merchant.securenexpay.com/checkout/pay.php?payment_uid=PAY...",
"provider_checkout_url": "https://secure.securenexpay.com/api/execute/xxxx"
}{
"success": false,
"message": "Missing request signature."
}{
"success": false,
"message": "Invalid request signature."
}{
"success": false,
"message": "Unauthorized domain.",
"allowed_domain": "shop.example.com",
"request_domain": "otherdomain.com",
"field": "webhook_url"
}{
"success": false,
"message": "Provider payment creation failed.",
"provider_response": {
"status": 0,
"message": "Invalid API Request."
}
}If a merchant has an allowed domain, then success_url, cancel_url, and webhook_url must use the same domain.
Allowed domain: shop.example.com Allowed: https://shop.example.com/payment-success https://shop.example.com/checkout/cancel https://shop.example.com/api/webhook Not allowed: https://example.com/payment-success https://sub.shop.example.com/payment-success https://otherdomain.com/payment-success
shop.example.com, only shop.example.com works. Main domain and other subdomains do not work unless configured separately.GET https://merchant.securenexpay.com/api/payment-status.php?public_key=pk_live_xxxxx&payment_uid=PAY20260614123456xxxx
| Parameter | Required | Description |
|---|---|---|
| public_key | Yes | Merchant public key. |
| payment_uid | Yes | SecureNexPay payment UID. |
https://merchant.securenexpay.com/api/payment-status.php?public_key=pk_live_xxxxx&payment_uid=PAY20260614123456xxxx
{
"success": true,
"payment_uid": "PAY20260614123456xxxx",
"order_id": "ORDER1001",
"amount": "190.00",
"net_amount": "190.00",
"payment_method": "bkash",
"transaction_id": "ABC123456",
"status": "COMPLETED",
"created_at": "2026-06-14 12:20:00",
"paid_at": "2026-06-14 12:30:00"
}
{
"success": false,
"message": "Public key is required."
}
When payment is completed, SecureNexPay sends a POST request to the merchant webhook URL.
{
"payment_uid": "PAY20260614123456xxxx",
"order_id": "ORDER1001",
"amount": "190.00",
"net_amount": "190.00",
"status": "COMPLETED",
"payment_method": "bkash",
"transaction_id": "ABC123456",
"paid_at": "2026-06-14 12:30:00"
}X-SecureNexPay-Signature: generated_hmac_signature
webhook_signature = HMAC_SHA256(raw_webhook_body, secret_key)
Your webhook endpoint must return HTTP 200-299 after successful processing.
{
"success": true,
"message": "Webhook processed."
}{
"success": false,
"message": "Invalid webhook signature."
}If merchant webhook fails, SecureNexPay retries delivery automatically.
| Status | Meaning |
|---|---|
| PENDING | Payment created but not paid yet. |
| COMPLETED | Payment successfully completed. |
| FAILED | Payment failed. |
| CANCELLED | Customer cancelled payment. |
For WooCommerce stores, install the official SecureNexPay WooCommerce Gateway plugin and configure:
Public Key Secret Key Create Payment API URL Payment Status API URL
The plugin automatically generates:
Webhook URL Return URL Cancel URL Request Signature Timestamp Nonce
Customer ↓ Merchant Website ↓ create-payment.php ↓ SecureNexPay Create Payment API ↓ checkout_url ↓ Customer Payment Page ↓ Payment Completed ↓ Signed Webhook ↓ Merchant webhook.php ↓ Verify Signature + Update Order ↓ Order Completed
Correct Public Key Correct Secret Signature Correct Timestamp Unique Nonce Correct Allowed Domain Expected: Payment created successfully
Remove X-SecureNexPay-Signature header Expected: 401 Missing request signature
X-SecureNexPay-Signature: wrong123 Expected: 401 Invalid request signature
Allowed domain: shop.example.com webhook_url: https://otherdomain.com/webhook Expected: 403 Unauthorized domain
Send same timestamp + nonce + signature twice Expected: First request may pass Second request should fail