Logo
Examples

Create Withdraw Example

Complete example of creating a withdraw/payout using One2Pays API.

Overview

This example shows how to:

  1. Create a withdraw to a bank account
  2. Handle the withdraw response
  3. Monitor withdraw status

Complete Example

import crypto from 'crypto';

const API_KEY = process.env.PAYMENT_API_KEY!;
const API_SECRET = process.env.PAYMENT_API_SECRET!;

// Helper function to create HMAC signature
function createSignature(
  timestamp: string,
  body: string,
  secret: string
): string {
  // Signature format: HMAC-SHA256(timestamp + "." + rawBody, secretKey)
  const message = `${timestamp}.${body}`;
  return crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
}

// Create withdraw
export async function createWithdraw(
  amount: string,
  customerBankAccount: {
    name: string;
    number: string;
    code: string;
  },
  referenceId: string
) {
  const method = 'POST';
  const path = '/api/v1/withdraws';
  const body = JSON.stringify({
    amount, // String like "1000.00"
    currency: 'THB',
    referenceId,
    destinationType: 'bank_account',
    customerBankAccountName: customerBankAccount.name,
    customerBankAccountNumber: customerBankAccount.number,
    customerBankCode: customerBankAccount.code,
    description: `Payout for ${referenceId}`,
    idempotencyKey: `${referenceId}-${Date.now()}`,
  });
  const timestamp = Date.now().toString(); // milliseconds

  const signature = createSignature(timestamp, body, API_SECRET);

  const response = await fetch(`https://api.example.com${path}`, {
    method,
    headers: {
      'X-API-Key': API_KEY,
      'X-Timestamp': timestamp,
      'X-Signature': `sha256=${signature}`,
      'Content-Type': 'application/json',
    },
    body,
  });

  const result = await response.json();

  if (!result.success) {
    throw new Error(result.error.message);
  }

  return result.data;
}

// Usage
async function payoutToVendor(
  orderId: string,
  vendorBankAccount: {
    name: string;
    number: string;
    code: string;
  }
) {
  try {
    const withdraw = await createWithdraw(
      '500.00',
      vendorBankAccount,
      `payout-${orderId}`
    );

    console.log('Withdraw created:', withdraw.id);
    console.log('Withdraw status:', withdraw.status);

    // Monitor withdraw status via webhook or polling
    return withdraw;
  } catch (error) {
    console.error('Withdraw creation failed:', error);
    throw error;
  }
}

Error Handling

Always handle errors when creating withdraws:

try {
  const withdraw = await createWithdraw(amount, customerBankAccount, referenceId);

  if (withdraw.status === 'pending' || withdraw.status === 'processing') {
    // Withdraw is being processed
    console.log('Withdraw initiated successfully');
  }
} catch (error) {
  if (error.message.includes('INSUFFICIENT_BALANCE')) {
    // Handle insufficient funds
    console.error('Merchant account balance is insufficient');
  } else if (error.message.includes('INVALID_BANK_CODE')) {
    // Handle invalid bank code
    console.error('Invalid bank code');
  } else {
    // Handle other errors
    console.error('Withdraw creation failed:', error);
  }
}

Monitoring Withdraw Status

Monitor withdraw status via webhooks or polling:

// Via webhook (recommended)
async function handleWithdrawWebhook(event: any) {
  if (event.type === 'withdraw.paid') {
    console.log('Withdraw completed:', event.data.id);
    // Update your system
  } else if (event.type === 'withdraw.failed') {
    console.log('Withdraw failed:', event.data.id);
    // Handle failure
  }
}

// Via polling
async function checkWithdrawStatus(withdrawId: string) {
  const withdraw = await getWithdraw(withdrawId);

  if (withdraw.status === 'paid') {
    console.log('Withdraw completed');
  } else if (withdraw.status === 'failed') {
    console.log('Withdraw failed');
  } else {
    // Still processing, check again later
    setTimeout(() => checkWithdrawStatus(withdrawId), 5000);
  }
}

On this page