Logo
Examples

Accept Payment Example

Complete example of accepting a payment using One2Pays API.

Overview

This example shows how to:

  1. Create a payment with required fields
  2. Handle the payment response with nextAction
  3. Redirect customer to payment page
  4. Handle webhook notifications

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 payment
export async function createPayment(
  orderId: string,
  amount: string,
  customerBankAccount: {
    name: string;
    number: string;
    code: string;
  }
) {
  const method = 'POST';
  const path = '/api/v1/payments';
  const body = JSON.stringify({
    amount, // Already a string like "1000.00"
    currency: 'THB',
    referenceId: `order-${orderId}`,
    paymentMethod: 'promptpay',
    customerBankAccountName: customerBankAccount.name,
    customerBankAccountNumber: customerBankAccount.number,
    customerBankCode: customerBankAccount.code,
    description: `Payment for order #${orderId}`,
    metadata: {
      order_id: orderId,
    },
    idempotencyKey: `order-${orderId}-${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 in API route (Next.js)
export async function POST(request: Request) {
  try {
    const { orderId, amount, customerBankAccount } = await request.json();

    const payment = await createPayment(orderId, amount, customerBankAccount);

    // Handle nextAction
    if (payment.nextAction?.type === 'use_payment_app') {
      return Response.json({
        success: true,
        paymentId: payment.id,
        redirectUrl: payment.nextAction.paymentAppUrl,
      });
    } else if (payment.nextAction?.type === 'redirect') {
      return Response.json({
        success: true,
        paymentId: payment.id,
        redirectUrl: payment.nextAction.redirectUrl,
      });
    }

    return Response.json({
      success: true,
      paymentId: payment.id,
      status: payment.status,
    });
  } catch (error) {
    return Response.json(
      { success: false, error: error instanceof Error ? error.message : 'Unknown error' },
      { status: 400 }
    );
  }
}

Frontend Integration

'use client';

import { useState } from 'react';

export function PaymentButton({ 
  orderId, 
  amount, 
  customerBankAccount 
}: { 
  orderId: string; 
  amount: string;
  customerBankAccount: {
    name: string;
    number: string;
    code: string;
  };
}) {
  const [loading, setLoading] = useState(false);

  const handlePayment = async () => {
    setLoading(true);
    try {
      const response = await fetch('/api/payments/create', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ 
          orderId, 
          amount,
          customerBankAccount,
        }),
      });

      const result = await response.json();

      if (result.success && result.redirectUrl) {
        window.location.href = result.redirectUrl;
      } else {
        alert('Payment creation failed');
      }
    } catch (error) {
      console.error('Error:', error);
      alert('An error occurred');
    } finally {
      setLoading(false);
    }
  };

  return (
    <button onClick={handlePayment} disabled={loading}>
      {loading ? 'Processing...' : 'Pay Now'}
    </button>
  );
}

On this page