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.

Integration Flow Diagrams

The following sequence diagrams illustrate the complete integration flows for deposit and withdrawal operations. These diagrams show the interaction between your application, FundPay APIs, and the banking systems. Click on any diagram to view it in full size.

Deposit Flow

This diagram shows the complete flow for processing deposit transactions, including signature generation, API calls, and webhook notifications.

Deposit Sequence Diagram - Shows the flow of deposit transactions from initiation to completion
Click to expand

Withdrawal Flow

This diagram illustrates the withdrawal process, including the additional security measures and bank account verification steps required for fund disbursements.

Withdrawal Sequence Diagram - Shows the flow of withdrawal transactions including security verification
Click to expand

Key Integration Points

  • Signature Generation: Both flows require proper HMAC signature generation for API authentication
  • Webhook Handling: Implement webhook endpoints to receive real-time transaction status updates
  • Error Handling: Plan for various error scenarios and implement appropriate retry mechanisms
  • Security: Withdrawal flows include additional verification steps for enhanced security

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.fundpay24h.com/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.

📝 Important Note: Object Flattening

When generating signatures, nested objects in the API request must be flattened into individual fields. For example:

Original nested object:

"source_bank_account": {
  "bank_code": "kbank",
  "account_name": "TEST HEELO",
  "account_number": "1234567"
}

Flattened for signature generation:

"source_account_bank_code": "kbank"
"source_account_name": "TEST HEELO"
"source_account_no": "1234567"

Example Signature Generation

Request Parameters

{
  "merchant_id": "d0bf1184-c1c9-4101-b034-97e3b44edf4e",
  "amount": "1000",
  "currency": "THB",
  "reference": "ttt",
  "payment_method": "withdrawal",
  "frontend_return_url": "https://example.com/return",
  "backend_return_url": "https://example.com/webhook",
  "source_account_bank_code": "kbank",
  "source_account_name": "TEST HEELO",
  "source_account_no": "1234567",
  "timestamp": "2025-07-29T21:23:29+07:00"
}

Secret Key

YOUR_SECRET_KEY

URL-Encoded String (Sorted Parameters)

amount=3269&backend_return_url=https%3A%2F%2Fexample.com%2Fwebhook&currency=THB&frontend_return_url=https%3A%2F%2Fexample.com%2Freturn&merchant_id=79703311-ab77-4f93-a8b8-70c21a2c8c79&payment_method=qr_payment&reference=deposit_281753758186604&source_account_bank_code=kbank&source_account_name=TEST+HEELO&source_account_no=1234567&timestamp=2025-07-29T22%3A10%3A00%2B07%3A00

Generated Signature (HMAC-SHA256)

7dd83af0dcae52d6f2ae5e8672f41fc067c1d587a9ab932495c38dca2e70e1e5

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

// Example usage for withdrawal
const payload = {
  merchant_id: '79703311-ab77-4f93-a8b8-70c21a2c8c79',
  amount: 1000,
  currency: 'THB',
  reference: 'ttt',
  payment_method: 'withdrawal',
  frontend_return_url: 'https://example.com/return',
  backend_return_url: 'https://example.com/webhook',
  source_account_bank_code: 'kbank',
  source_account_name: 'TEST HEELO',
  source_account_no: '1234567',
  timestamp: '2025-07-29T21:23:29+07:00'
};

const secretKey = 'YOUR_SECRET_KEY';
const signature = generateSignature(payload, secretKey);

📝 Important Note: Object Flattening

When generating signatures, nested objects in the API request must be flattened into individual fields. For example:

Original nested object:

"source_bank_account": {
  "bank_code": "kbank",
  "account_name": "TEST HEELO",
  "account_number": "1234567"
}

Flattened for signature generation:

"source_account_bank_code": "kbank"
"source_account_name": "TEST HEELO"
"source_account_no": "1234567"

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

/deposit/deposits

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_payment or bank_transfer)
frontend_return_urlstringURL to redirect customer after payment
backend_return_urlstringURL for webhook notifications
timestampstringISO 8601 timestamp
source_bank_accountobjectThe source bank account details (optional)
destination_bank_accountobjectThe destination bank account details (optional)
customer_emailstringCustomer Email (optional)
customer_phone_numberstringCustomer phone number (optional)
descriptionstringAdditional details about the deposit (optional)
signaturestringHMAC-SHA256 signature of the request
Example Request:
POST /deposit/deposits
{
  "merchant_id": "MERCHANT_DEV_20250522_ABCDEFGHIJKLMN",
  "amount": 123124,
  "currency": "THB",
  "reference": "ORD1026761",
  "payment_method": "bank_transfer",
  "frontend_return_url": "https://localhost:3000/frontend",
  "backend_return_url": "https://localhost:3000/backend",
  "source_bank_account": {
    "bank_code": "kbank",
    "account_number": "12345678",
    "account_name": "John Doe"
  },
  "timestamp": "2025-05-20T16:10:02.941Z",
  "customer_email": "[email protected]",
  "customer_phone_number": "+66812345678",
  "description": "Payment for order ORD1026761",
  "signature": "87df2dcd4fbfe782ba9035635ea98a1fc9a4c74ff741e3fcf526ce3711940414"
}

Response Body

FieldTypeDescription
codeintegerResponse code (2000 for success)
messagestringResponse message
data.idstringUnique deposit ID
data.web_payment_urlstringURL for payment page
data.payment_tokenstringToken to identify this payment
data.total_amountnumberTotal amount to be paid including any fees
data.destination_bank_accountobjectThe destination bank account details
data.destination_bankobjectDestination bank information
data.expires_atstringExpiration timestamp
Example Response:
{
  "code": 2000,
  "message": "Deposit created successfully",
  "data": {
    "id": "deposit_dev_ERKWB1VFRJ7TjBpHcabGaOpgr6AFpNOn",
    "web_payment_url": "https://customer-dev.fundpay.app/payment/EV0ZZMILAKMX5iSMqZKPXjHBeUQoA2k6C4ST7Gn7DEz0CR26KD4gWCADJD5TFK8m",
    "payment_token": "EV0ZZMILAKMX5iSMqZKPXjHBeUQoA2k6C4ST7Gn7DEz0CR26KD4gWCADJD5TFK8m",
    "total_amount": 123124.37,
    "expires_at": "2025-05-21T16:09:32.305746742Z",
    "destination_bank_account": {
      "bank_code": "kbank",
      "account_number": "12345667",
      "account_name": "John Doe",
      "account_promptpay": "1234567890123"
    },
    "destination_bank": {
      "code": "004",
      "name": {
        "th": "ธนาคารกสิกรไทย",
        "en": "Kasikorn Bank"
      },
      "logo_url": "https://fundpay24h.com/bank-logo/kbank.png"
    }
  }
}
GET

Get Deposit Status

/deposit/deposits/{id}

Description

Retrieves the current status of a deposit by its ID.

Path Parameters

ParameterTypeDescription
idstringDeposit ID to retrieve
Example Request:
GET /deposit/deposits/deposit_dev_ERKWB1VFRJ7TjBpHcabGaOpgr6AFpNOn

Response Body

FieldTypeDescription
codeintegerResponse code (2000 for success)
messagestringResponse message
data.idstringUnique deposit ID
data.statusstringDeposit status (e.g., pending_approve, completed, failed)
data.total_amountnumberTotal deposit amount
data.currencystringCurrency code
data.referencestringMerchant reference
data.created_atstringCreation timestamp
data.updated_atstringLast update timestamp
data.payment_methodstringPayment method used
data.source_bank_accountobjectSource bank account details
data.destination_bank_accountobjectDestination bank account details
data.source_bankobjectSource bank information
data.destination_bankobjectDestination bank information
data.merchantobjectMerchant information
Example Response:
{
  "code": 2000,
  "message": "Get deposit successfully",
  "data": {
    "id": "deposit_dev_ERKWB1VFRJ7TjBpHcabGaOpgr6AFpNOn",
    "status": "pending_approve",
    "total_amount": 123123.1,
    "currency": "THB",
    "reference": "ORD1026761",
    "payment_method": "bank_transfer",
    "created_at": "2025-05-20T17:03:40.401157Z",
    "updated_at": "2025-05-20T17:03:40.401157Z",
    "source_bank_account": {
      "bank_code": "kbank",
      "account_number": "12345678",
      "account_name": "John Doe"
    },
    "destination_bank_account": {
      "bank_code": "kbank",
      "account_number": "87654321",
      "account_name": "Jane Smith"
    },
    "source_bank": {
      "code": "004",
      "name": {
        "th": "ธนาคารกสิกรไทย",
        "en": "Kasikorn Bank"
      },
      "logo_url": "https://fundpay24h.com/bank-logo/kbank.png"
    },
    "destination_bank": {
      "code": "004",
      "name": {
        "th": "ธนาคารกสิกรไทย",
        "en": "Kasikorn Bank"
      },
      "logo_url": "https://fundpay24h.com/bank-logo/kbank.png"
    },
    "merchant": {
      "merchant_code": "MERCHANT_DEV_20250522",
      "legal_name": {
        "th": "บริษัท เทสต์ จำกัด",
        "en": "Test Company Limited"
      }
    }
  }
}

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.

Webhook Payloads

When transaction statuses change, FundPay will send webhook notifications to your backend server. The webhook contains all the necessary information about the transaction.

Deposit Webhook Payload

When a deposit status changes, FundPay will send a webhook notification with the following payload structure.

{
  "amount": 1500.23,
  "status": "approved",
  "signature": "e666fcb596d6213b9807930909b77f37a2733d2e6a0835d97c37837b4e10f01e",
  "merchant_id": "c513667a-36c5-4c2a-bbba-e72e632aa906",
  "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
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)

Webhook Signature Verification

To ensure webhook authenticity and security, you must verify the signature included in each webhook payload. This prevents malicious actors from sending fake webhook notifications to your server.

Verification Process

  1. 1
    Extract Webhook Payload

    Receive the webhook payload and extract all fields except the signature.

  2. 2
    Sort Parameters Alphabetically

    Sort all payload fields (excluding signature) in alphabetical order by key name.

  3. 3
    Create URL-Encoded String

    Build a URL-encoded query string from the sorted parameters.

  4. 4
    Generate Expected Signature

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

  5. 5
    Compare Signatures

    Use a constant-time comparison to verify the generated signature matches the received signature.

Code Examples

// Node.js Example
const crypto = require('crypto');

function verifyWebhookSignature(payload, receivedSignature, secretKey) {
  // Extract signature from payload
  const { signature, ...payloadWithoutSignature } = payload;
  
  // Sort parameters alphabetically
  const sortedKeys = Object.keys(payloadWithoutSignature).sort();
  
  // Create values object
  const values = {};
  for (const key of sortedKeys) {
    values[key] = String(payloadWithoutSignature[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 expected signature
  const expectedSignature = crypto
    .createHmac('sha256', secretKey)
    .update(stringToSign)
    .digest('hex');
  
  // Use constant-time comparison for security
  return crypto.timingSafeEqual(
    Buffer.from(receivedSignature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  );
}

// Express.js webhook handler example
const express = require('express');
const app = express();

// Middleware to get raw body for signature verification
app.use('/webhook', express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  try {
    // Parse the JSON payload
    const payload = JSON.parse(req.body.toString());
    
    // Verify signature
    const secretKey = process.env.FUNDPAY_SECRET_KEY;
    if (!secretKey) {
      return res.status(500).json({ error: 'Secret key not configured' });
    }
    
    const isValid = verifyWebhookSignature(payload, payload.signature, secretKey);
    
    if (!isValid) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
    
    // Process webhook payload
    console.log('Valid webhook received:', payload);
    
    // Update your database based on transaction status
    // await updateTransactionStatus(payload.transaction_id, payload.status);
    
    res.status(200).json({ success: true });
  } catch (error) {
    console.error('Webhook processing error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

🔒 Security Best Practices

  • Always verify signatures before processing webhook data to prevent unauthorized requests.
  • Use constant-time comparison (crypto.timingSafeEqual) to prevent timing attacks.
  • Store secret keys securely in environment variables, never in code.
  • Disable body parser when you need access to the raw request body for signature verification.
  • Implement proper error handling and logging for security monitoring.

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

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.