This guide provides comprehensive documentation for integrating with the FundPay payment platform. Follow the steps below to implement a secure and reliable integration.
FundPay provides two methods of authentication for API requests. Choose the method that best fits your integration needs.
Use API keys for simple authentication. Include your API key in the request header.
x-api-key: YOUR_API_KEY
Pros: Simple to implement, minimal setup required.
Cons: Less secure than signature-based authentication.
Generate a cryptographic signature for each request for enhanced security.
{ ... "signature": "GENERATED_SIGNATURE" }
Pros: Highly secure, prevents tampering and replay attacks.
Cons: More complex to implement.
We strongly recommend using signature-based authentication for production environments. API key authentication is suitable for testing and development but provides less security for live transactions.
Your API keys are available in your merchant dashboard. Each API key has specific permissions and can be restricted to certain IP addresses for additional security.
Never share your API keys or include them in client-side code. Always store API keys securely in environment variables or a secure key management system.
// JavaScript Example
const axios = require('axios');
async function makeApiRequest() {
try {
const response = await axios.get('https://api.fundpay.co/api/v1/merchant/balance', {
headers: {
'x-api-key': 'YOUR_API_KEY'
}
});
console.log(response.data);
} catch (error) {
console.error('Error:', error);
}
}
Generating a valid signature for your API requests involves creating an HMAC-SHA256 hash of your request parameters using your secret key.
Collect all the parameters for your API request (excluding the signature itself).
Sort all parameter keys in alphabetical order (A-Z).
Create a URL-encoded string of key-value pairs in the format: key1=value1&key2=value2
Create an HMAC-SHA256 hash of the URL-encoded string using your merchant secret key.
Include the generated signature in your API request as the signature
parameter.
{ "merchant_id": "MERCHANT_DEV_20250522_ABCDEFGHIJKLMN", "amount": "1000", "currency": "THB", "reference": "ORDER123456", "payment_method": "qr", "frontend_return_url": "https://example.com/return", "backend_return_url": "https://example.com/webhook", "timestamp": "2025-05-20T15:30:45.123Z" }
YOUR_SECRET_KEY
amount=1000&backend_return_url=https%3A%2F%2Fexample.com%2Fwebhook¤cy=THB&frontend_return_url=https%3A%2F%2Fexample.com%2Freturn&merchant_id=MERCHANT_DEV_20250522_ABCDEFGHIJKLMN&payment_method=qr&reference=ORDER123456×tamp=2025-05-20T15%3A30%3A45.123Z
7d5a8e68f45f42b9a8f7c5e6d4c3b2a1e0f9d8c7b6a5948372615f4e3d2c1b0a
Below are code samples for generating signatures in different programming languages. You can also use the interactive form to generate a signature for your API request.
// JavaScript Example (Node.js)
const crypto = require('crypto');
function generateSignature(payload, secretKey) {
// Sort keys alphabetically
const sortedKeys = Object.keys(payload).sort();
// Create values object
const values = {};
for (const key of sortedKeys) {
values[key] = String(payload[key]);
}
// Create string to sign (URL-encoded key-value pairs)
const params = new URLSearchParams();
for (const key of sortedKeys) {
params.append(key, values[key]);
}
const stringToSign = params.toString();
// Generate HMAC
const hmac = crypto.createHmac('sha256', secretKey);
hmac.update(stringToSign);
return hmac.digest('hex');
}
Add this signature to your request payload in the signature
field.
FundPay provides a comprehensive set of API endpoints for managing deposits and withdrawals. Below are the detailed specifications for each endpoint.
Creates a new deposit request for a merchant. Supports both QR code and bank transfer payment methods.
Field | Type | Description |
---|---|---|
merchant_id | string | Your merchant ID provided by FundPay |
amount | number | Amount in the smallest currency unit |
currency | string | Currency code (e.g., THB) |
reference | string | Your unique reference for this transaction |
payment_method | string | Payment method (qr or bank_transfer) |
frontend_return_url | string | URL to redirect customer after payment |
backend_return_url | string | URL for webhook notifications |
timestamp | string | ISO 8601 timestamp |
signature | string | HMAC-SHA256 signature of the request |
{ "merchant_id": "MERCHANT_DEV_20250522_ABCDEFGHIJKLMN", "amount": 1000, "currency": "THB", "reference": "ORDER123456", "payment_method": "qr", "frontend_return_url": "https://example.com/return", "backend_return_url": "https://example.com/webhook", "timestamp": "2025-05-20T15:30:45.123Z", "signature": "7d5a8e68f45f42b9a8f7c5e6d4c3b2a1e0f9d8c7b6a5948372615f4e3d2c1b0a" }
Field | Type | Description |
---|---|---|
code | integer | Response code (2000 for success) |
message | string | Response message |
data.id | string | Unique deposit ID |
data.payment_url | string | URL for payment page |
data.promptpay | string | QR code data (if payment_method is qr) |
data.bank_details | object | Bank details (if payment_method is bank_transfer) |
data.expires_at | string | Expiration timestamp |
{ "code": 2000, "message": "Success", "data": { "id": "deposit_dev_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "payment_url": "https://pay.fundpay.co/checkout/ABCDEFGHIJKLMNOPQRSTUVWXYZ", "promptpay": "00020101021229...", "expires_at": "2025-05-20T16:30:45.123Z" } }
Retrieves the current status of a deposit by its ID.
Parameter | Type | Description |
---|---|---|
id | string | Deposit ID to retrieve |
Field | Type | Description |
---|---|---|
code | integer | Response code (2000 for success) |
message | string | Response message |
data.id | string | Unique deposit ID |
data.status | string | Deposit status (pending, completed, failed) |
data.amount | number | Deposit amount |
data.currency | string | Currency code |
data.reference | string | Merchant reference |
data.created_at | string | Creation timestamp |
data.updated_at | string | Last update timestamp |
{ "code": 2000, "message": "Success", "data": { "id": "deposit_dev_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "status": "completed", "amount": 1000, "currency": "THB", "reference": "ORDER123456", "created_at": "2025-05-20T15:30:45.123Z", "updated_at": "2025-05-20T15:35:12.456Z" } }
Follow these security best practices to ensure your integration with FundPay is secure and reliable:
If you have any questions or need assistance with your integration, please contact our support team at [email protected].
FundPay sends webhook notifications to your backend server when transaction statuses are updated. This guide explains how to properly handle these webhook notifications.
Webhooks are HTTP callbacks that notify your system when events occur in the FundPay platform. When a transaction status changes, FundPay will send a POST request to your specified backend URL with details about the event.
When a deposit status changes, FundPay will send a webhook notification to your backend server. The webhook contains all the necessary information about the deposit transaction.
{
"amount": 1500.23,
"status": "approved",
"signature": "e666fcb596d6213b9807930909b77f37a2733d2e6a0835d97c37837b4e10f01e",
"merchant_id": "c513667a-36c5-4c2a-bbba-e72e632aa906",
"processed_by": "[email protected]",
"reference_id": "ORD-12345",
"transaction_id": "deposit_dev_EWuWJFgxR0NlrZFoJEm42ZOl3DHVfTL4",
"transaction_date": "2025-06-21T12:42:20Z",
"transaction_type": "deposit"
}
Field | Type | Description |
---|---|---|
amount | number | The transaction amount in the smallest currency unit |
status | string | Transaction status (approved, rejected, pending) |
signature | string | HMAC-SHA256 signature for verifying the webhook |
merchant_id | string | Your merchant ID |
processed_by | string | Email of the admin who processed the transaction |
reference_id | string | Your reference ID for this transaction |
transaction_id | string | FundPay's unique transaction ID |
transaction_date | string | ISO 8601 timestamp of the transaction |
transaction_type | string | Type of transaction (deposit) |
When a withdrawal status changes, FundPay will send a webhook notification to your backend server. The webhook contains detailed information about the withdrawal transaction, including a signature for verification.
{
"amount": 1000,
"remark": "my note",
"status": "rejected",
"signature": "858dfd034ef7b40298a8c69fea6961b74967c887255a78a4588a96f9dca367c6",
"merchant_id": "c513667a-36c5-4c2a-bbba-e72e632aa906",
"processed_by": "[email protected]",
"reference_id": "ttt",
"transaction_id": "withdrawal_dev_EXPjbvx2idcBO83W5d8dTtHg3jASULPN",
"transaction_date": "2025-06-21T12:42:34Z",
"transaction_type": "withdrawal"
}
Field | Type | Description |
---|---|---|
amount | number | The transaction amount in the smallest currency unit |
remark | string | Additional note or comment about the transaction |
status | string | Transaction status (approved, rejected, pending) |
signature | string | HMAC-SHA256 signature for verifying the webhook |
merchant_id | string | Your merchant ID |
processed_by | string | Email of the admin who processed the transaction |
reference_id | string | Your reference ID for this transaction |
transaction_id | string | FundPay's unique transaction ID |
transaction_date | string | ISO 8601 timestamp of the transaction |
transaction_type | string | Type of transaction (withdrawal) |
Follow these steps to properly implement webhook handling in your application.
Contact FundPay support to register your webhook URL. This URL should point to an endpoint on your server that will receive webhook notifications.
Create an endpoint on your server to receive webhook notifications. This endpoint should:
// Using Express.js
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// Your FundPay secret key
const SECRET_KEY = process.env.FUNDPAY_SECRET_KEY;
// Webhook endpoint
app.post('/webhooks/fundpay', async (req, res) => {
try {
const payload = req.body;
console.log('Received webhook:', payload);
// Check transaction type
if (payload.transaction_type === 'withdrawal') {
// Verify signature for withdrawal webhooks
const receivedSignature = payload.signature;
// Create a copy of the payload without the signature for verification
const payloadForVerification = {...payload};
delete payloadForVerification.signature;
// Sort keys alphabetically
const sortedPayload = {};
Object.keys(payloadForVerification).sort().forEach(key => {
sortedPayload[key] = payloadForVerification[key];
});
// Create string to sign
const stringToSign = Object.entries(sortedPayload)
.map(([key, value]) => `${key}=${value}`)
.join('&');
// Generate signature
const calculatedSignature = crypto
.createHmac('sha256', SECRET_KEY)
.update(stringToSign)
.digest('hex');
// Verify signature
if (calculatedSignature !== receivedSignature) {
console.error('Invalid signature');
return res.status(400).send('Invalid signature');
}
}
// Process the webhook based on transaction type and status
if (payload.transaction_type === 'deposit') {
await processDepositWebhook(payload);
} else if (payload.transaction_type === 'withdrawal') {
await processWithdrawalWebhook(payload);
}
// Acknowledge receipt of webhook
res.status(200).send('Webhook received');
} catch (error) {
console.error('Error processing webhook:', error);
res.status(500).send('Error processing webhook');
}
});
async function processDepositWebhook(payload) {
// Update your database based on deposit status
const { reference_id, status, amount, transaction_id } = payload;
// Example: Update order status in your database
// await db.orders.updateStatus(reference_id, status);
console.log(`Updated deposit status for ${reference_id} to ${status}`);
}
async function processWithdrawalWebhook(payload) {
// Update your database based on withdrawal status
const { reference_id, status, amount, transaction_id } = payload;
// Example: Update withdrawal request in your database
// await db.withdrawals.updateStatus(reference_id, status);
console.log(`Updated withdrawal status for ${reference_id} to ${status}`);
}
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
<?php
// Get the webhook payload
$payload = json_decode(file_get_contents('php://input'), true);
$secret_key = getenv('FUNDPAY_SECRET_KEY');
// Log the webhook
file_put_contents('webhook_log.txt', date('Y-m-d H:i:s') . ' - ' . json_encode($payload) . "\n", FILE_APPEND);
// Check transaction type
if ($payload['transaction_type'] === 'withdrawal') {
// Verify signature for withdrawal webhooks
$received_signature = $payload['signature'];
// Create a copy of the payload without the signature for verification
$payload_for_verification = $payload;
unset($payload_for_verification['signature']);
// Sort keys alphabetically
ksort($payload_for_verification);
// Create string to sign
$string_to_sign = '';
foreach ($payload_for_verification as $key => $value) {
$string_to_sign .= $key . '=' . $value . '&';
}
$string_to_sign = rtrim($string_to_sign, '&');
// Generate signature
$calculated_signature = hash_hmac('sha256', $string_to_sign, $secret_key);
// Verify signature
if ($calculated_signature !== $received_signature) {
http_response_code(400);
echo 'Invalid signature';
exit;
}
}
// Process the webhook based on transaction type and status
if ($payload['transaction_type'] === 'deposit') {
process_deposit_webhook($payload);
} else if ($payload['transaction_type'] === 'withdrawal') {
process_withdrawal_webhook($payload);
}
// Acknowledge receipt of webhook
http_response_code(200);
echo 'Webhook received';
function process_deposit_webhook($payload) {
// Update your database based on deposit status
$reference_id = $payload['reference_id'];
$status = $payload['status'];
$amount = $payload['amount'];
$transaction_id = $payload['transaction_id'];
// Example: Update order status in your database
// $db->query("UPDATE orders SET status = ? WHERE reference_id = ?", [$status, $reference_id]);
error_log("Updated deposit status for {$reference_id} to {$status}");
}
function process_withdrawal_webhook($payload) {
// Update your database based on withdrawal status
$reference_id = $payload['reference_id'];
$status = $payload['status'];
$amount = $payload['amount'];
$transaction_id = $payload['transaction_id'];
// Example: Update withdrawal request in your database
// $db->query("UPDATE withdrawals SET status = ? WHERE reference_id = ?", [$status, $reference_id]);
error_log("Updated withdrawal status for {$reference_id} to {$status}");
}
?>