Logo
API ReferencePayments

Create Payment

Creates a new payment transaction. The payment will be processed asynchronously, and you'll receive a nextAction in the response indicating what action to take next.

Endpoint

POST /api/v1/payments

Authentication

This endpoint requires HMAC Integration Authentication.

Request Parameters

ParameterTypeRequiredDescription
amountstringYesAmount as decimal string (e.g., "1000.00" = 10.00 THB)
currencystringNoCurrency code. Defaults to "THB"
referenceIdstringYesYour unique reference ID (alphanumeric, underscores, hyphens, dots, 1-255 chars)
paymentMethodstringYesPayment method: "promptpay" or "bank_transfer"
customerBankAccountNamestringYesCustomer's bank account name
customerBankAccountNumberstringYesCustomer's bank account number
customerBankCodestringYes3-digit Thai bank code (e.g., "004" for KBANK)
descriptionstringNoPayment description (max 255 characters)
metadataobjectNoAdditional metadata (key-value pairs)
idempotencyKeystringNoUnique key to prevent duplicate payments (recommended)
expiresInMinutesnumberNoPayment expiration time in minutes (5-1440, default based on payment method)

Integration Context

Your merchantId and integrationId are automatically provided from your integration credentials. You don't need to include them in the request.

Example Request

import crypto from 'crypto';

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

async function createPayment() {
  const method = 'POST';
  const path = '/api/v1/payments';
  const body = JSON.stringify({
    amount: '1000.00',
    currency: 'THB',
    referenceId: `order-${Date.now()}`,
    paymentMethod: 'promptpay',
    customerBankAccountName: 'John Doe',
    customerBankAccountNumber: '1234567890',
    customerBankCode: '004',
    description: 'Payment for order #12345',
    metadata: {
      order_id: '12345',
    },
    idempotencyKey: `order-12345-${Date.now()}`,
  });

  const timestamp = Date.now().toString();
  const message = `${timestamp}.${body}`;
  const signature = crypto
    .createHmac('sha256', API_SECRET)
    .update(message)
    .digest('hex');

  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) {
    console.log('Payment created:', result.data.id);
    console.log('Status:', result.data.status);
    console.log('Next action:', result.data.nextAction);

    // Handle nextAction
    if (result.data.nextAction?.type === 'use_payment_app') {
      // Redirect customer to payment app
      window.location.href = result.data.nextAction.paymentAppUrl;
    } else if (result.data.nextAction?.type === 'redirect') {
      // Redirect to custom URL
      window.location.href = result.data.nextAction.redirectUrl;
    }
  } else {
    console.error('Error:', result.error);
  }
}

createPayment();

Response

Success Response (201 Created)

{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "amount": "1000.00",
    "currency": "THB",
    "status": "processing",
    "paymentMethod": "promptpay",
    "referenceId": "order-12345",
    "description": "Payment for order #12345",
    "metadata": {
      "order_id": "12345"
    },
    "clientSecret": null,
    "nextAction": {
      "type": "use_payment_app",
      "paymentAppUrl": "https://pay.example.com/docs/pay/secure-token-here"
    },
    "confirmedAt": null,
    "capturedAt": null,
    "canceledAt": null,
    "expiresAt": "2024-01-01T01:00:00.000Z",
    "createdAt": "2024-01-01T00:00:00.000Z",
    "updatedAt": "2024-01-01T00:00:00.000Z"
  }
}

Error Response (400 Bad Request)

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "amount must be a valid decimal number",
    "metadata": {
      "field": "amount"
    }
  }
}

Next Action Types

After creating a payment, the response includes a nextAction field that tells you what to do next:

use_payment_app

Redirect the customer to One2Pays's payment app to complete the payment:

{
  "type": "use_payment_app",
  "paymentAppUrl": "https://pay.example.com/docs/pay/secure-token-here"
}

Action: Redirect the customer to paymentAppUrl.

redirect

Redirect to a custom URL (if your integration has a custom redirect URL configured):

{
  "type": "redirect",
  "redirectUrl": "https://your-app.com/payment/{paymentId}"
}

Action: Redirect the customer to redirectUrl.

display_bank_transfer_instructions

Display bank transfer instructions to the customer:

{
  "type": "display_bank_transfer_instructions",
  "bankTransferInstructions": {
    "bankName": "Kasikorn Bank",
    "accountNumber": "1234567890",
    "accountName": "Example Company Ltd.",
    "amount": "1000.00",
    "reference": "ORDER-12345"
  }
}

Action: Display the bank transfer instructions to the customer.

Payment Creation Flow

Payment Status

After creation, payments typically start in one of these statuses:

  • processing - Payment is being processed
  • requires_payment_method - Payment method needs to be attached
  • requires_confirmation - Payment needs to be confirmed
  • requires_action - Additional action required from customer

Idempotency

Use Idempotency Keys

Always include an idempotencyKey in your requests to prevent duplicate payments if you need to retry a request.

If you make the same request twice with the same idempotencyKey, you'll receive the same payment object. This is useful for handling network errors and retries.

If you don't provide an idempotencyKey, the system will auto-generate one, but you won't be able to retry safely.

Error Codes

CodeDescription
VALIDATION_ERRORInvalid request parameters
INVALID_AMOUNTAmount must be a valid decimal number
INVALID_CURRENCYCurrency must be 'THB'
INVALID_REFERENCE_IDReference ID format is invalid
INVALID_BANK_CODEBank code must be a valid 3-digit Thai bank code
DUPLICATE_REFERENCE_IDReference ID already exists for this merchant
INVALID_CREDENTIALSAuthentication failed

See Also

On this page