API Documentation & Integration Guide

Back to Home

FundPay Integration Guide

This guide provides comprehensive documentation for integrating with the FundPay payment platform. Follow the steps below to implement a secure and reliable integration.

1. Authentication Methods

FundPay provides two methods of authentication for API requests. Choose the method that best fits your integration needs.

API Key Authentication

Use API keys for simple authentication. Include your API key in the request header.

Request Header

x-api-key: YOUR_API_KEY

Pros: Simple to implement, minimal setup required.

Cons: Less secure than signature-based authentication.

Signature Authentication

Generate a cryptographic signature for each request for enhanced security.

Request Body

{
  ...
  "signature": "GENERATED_SIGNATURE"
}

Pros: Highly secure, prevents tampering and replay attacks.

Cons: More complex to implement.

Security Recommendation

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.

API Key Management

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.

Important Security Notice

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.

Authentication Examples

API Key Authentication Example

// 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);
  }
}

2. Signature Generation

Generating a valid signature for your API requests involves creating an HMAC-SHA256 hash of your request parameters using your secret key.

Signature Generation Process

  1. 1

    Prepare Request Parameters

    Collect all the parameters for your API request (excluding the signature itself).

  2. 2

    Sort Parameters Alphabetically

    Sort all parameter keys in alphabetical order (A-Z).

  3. 3

    Create URL-Encoded String

    Create a URL-encoded string of key-value pairs in the format: key1=value1&key2=value2

  4. 4

    Generate HMAC-SHA256

    Create an HMAC-SHA256 hash of the URL-encoded string using your merchant secret key.

  5. 5

    Add Signature to Request

    Include the generated signature in your API request as the signature parameter.

Example Signature Generation

Request Parameters

{
  "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"
}

Secret Key

YOUR_SECRET_KEY

URL-Encoded String (Sorted Parameters)

amount=1000&backend_return_url=https%3A%2F%2Fexample.com%2Fwebhook&currency=THB&frontend_return_url=https%3A%2F%2Fexample.com%2Freturn&merchant_id=MERCHANT_DEV_20250522_ABCDEFGHIJKLMN&payment_method=qr&reference=ORDER123456&timestamp=2025-05-20T15%3A30%3A45.123Z

Generated Signature (HMAC-SHA256)

7d5a8e68f45f42b9a8f7c5e6d4c3b2a1e0f9d8c7b6a5948372615f4e3d2c1b0a

Important Notes

  • Always use the same sorting algorithm for consistent results.
  • Ensure all parameter values are properly URL-encoded.
  • The signature is case-sensitive and must be in lowercase hexadecimal format.
  • Include a timestamp parameter to prevent replay attacks.

3. Interactive Signature Tool

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.

Code Samples

// 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');
}

Interactive Signature Generator

Add this signature to your request payload in the signature field.

4. API Endpoints

FundPay provides a comprehensive set of API endpoints for managing deposits and withdrawals. Below are the detailed specifications for each endpoint.

Deposit Endpoints

POST

Create Deposit

/api/v1/deposit

Description

Creates a new deposit request for a merchant. Supports both QR code and bank transfer payment methods.

Request Body

FieldTypeDescription
merchant_idstringYour merchant ID provided by FundPay
amountnumberAmount in the smallest currency unit
currencystringCurrency code (e.g., THB)
referencestringYour unique reference for this transaction
payment_methodstringPayment method (qr or bank_transfer)
frontend_return_urlstringURL to redirect customer after payment
backend_return_urlstringURL for webhook notifications
timestampstringISO 8601 timestamp
signaturestringHMAC-SHA256 signature of the request
Example Request:
POST /api/v1/deposit
{
  "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"
}

Response Body

FieldTypeDescription
codeintegerResponse code (2000 for success)
messagestringResponse message
data.idstringUnique deposit ID
data.payment_urlstringURL for payment page
data.promptpaystringQR code data (if payment_method is qr)
data.bank_detailsobjectBank details (if payment_method is bank_transfer)
data.expires_atstringExpiration timestamp
Example Response:
{
  "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"
  }
}
GET

Get Deposit Status

/api/v1/deposit/{id}

Description

Retrieves the current status of a deposit by its ID.

Path Parameters

ParameterTypeDescription
idstringDeposit ID to retrieve
Example Request:
GET /api/v1/deposit/deposit_dev_ABCDEFGHIJKLMNOPQRSTUVWXYZ

Response Body

FieldTypeDescription
codeintegerResponse code (2000 for success)
messagestringResponse message
data.idstringUnique deposit ID
data.statusstringDeposit status (pending, completed, failed)
data.amountnumberDeposit amount
data.currencystringCurrency code
data.referencestringMerchant reference
data.created_atstringCreation timestamp
data.updated_atstringLast update timestamp
Example Response:
{
  "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"
  }
}

5. Security Best Practices

Follow these security best practices to ensure your integration with FundPay is secure and reliable:

Critical Security Guidelines

  • Never expose your secret key - Keep your merchant secret key secure and never include it in client-side code.
  • Generate signatures server-side - Always generate signatures on your server, never in client-side code.
  • Use HTTPS for all API communications - Never send API requests over unencrypted HTTP.
  • Validate webhook signatures - Always verify the signature of incoming webhook notifications.

Additional Recommendations

  • Implement proper error handling - Log and handle API interactions for better debugging and monitoring.
  • Store API keys securely - Use environment variables instead of hardcoding credentials in your codebase.
  • Rotate API keys periodically - Follow your organization's security policies for credential rotation.
  • Implement rate limiting - Protect your integration endpoints from abuse and potential DoS attacks.
  • Monitor API usage - Watch for unusual patterns that might indicate security issues or unauthorized access.

Need Help?

If you have any questions or need assistance with your integration, please contact our support team at [email protected].

6. Webhook Handling

FundPay sends webhook notifications to your backend server when transaction statuses are updated. This guide explains how to properly handle these webhook notifications.

Webhook Overview

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.

Deposit Status Webhooks

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.

Deposit Webhook Payload

{
  "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"
}

Payload Fields

FieldTypeDescription
amountnumberThe transaction amount in the smallest currency unit
statusstringTransaction status (approved, rejected, pending)
signaturestringHMAC-SHA256 signature for verifying the webhook
merchant_idstringYour merchant ID
processed_bystringEmail of the admin who processed the transaction
reference_idstringYour reference ID for this transaction
transaction_idstringFundPay's unique transaction ID
transaction_datestringISO 8601 timestamp of the transaction
transaction_typestringType of transaction (deposit)

Withdrawal Status Webhooks

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.

Withdrawal Webhook Payload

{
  "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"
}

Payload Fields

FieldTypeDescription
amountnumberThe transaction amount in the smallest currency unit
remarkstringAdditional note or comment about the transaction
statusstringTransaction status (approved, rejected, pending)
signaturestringHMAC-SHA256 signature for verifying the webhook
merchant_idstringYour merchant ID
processed_bystringEmail of the admin who processed the transaction
reference_idstringYour reference ID for this transaction
transaction_idstringFundPay's unique transaction ID
transaction_datestringISO 8601 timestamp of the transaction
transaction_typestringType of transaction (withdrawal)

Implementation Guide

Follow these steps to properly implement webhook handling in your application.

1. Configure Webhook URL

Contact FundPay support to register your webhook URL. This URL should point to an endpoint on your server that will receive webhook notifications.

2. Create Webhook Endpoint

Create an endpoint on your server to receive webhook notifications. This endpoint should:

  • Accept POST requests
  • Parse the JSON payload
  • Verify the webhook signature (for withdrawal webhooks)
  • Update your database based on the transaction status
  • Return a 200 OK response to acknowledge receipt

Code Examples

Node.js Example
// 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 Example
<?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}");
}
?>

3. Security Best Practices

  • Always verify signatures for withdrawal webhooks to ensure the request came from FundPay.
  • Use HTTPS for your webhook endpoint to ensure secure communication.
  • Implement idempotency to handle duplicate webhook notifications. Store the transaction_id and only process each unique webhook once.
  • Respond quickly with a 200 status code to acknowledge receipt, even before processing is complete.
  • Implement proper error handling to catch and log any issues during webhook processing.
  • Set up monitoring to track webhook deliveries and processing.