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
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | Amount as decimal string (e.g., "1000.00" = 10.00 THB) |
currency | string | No | Currency code. Defaults to "THB" |
referenceId | string | Yes | Your unique reference ID (alphanumeric, underscores, hyphens, dots, 1-255 chars) |
paymentMethod | string | Yes | Payment method: "promptpay" or "bank_transfer" |
customerBankAccountName | string | Yes | Customer's bank account name |
customerBankAccountNumber | string | Yes | Customer's bank account number |
customerBankCode | string | Yes | 3-digit Thai bank code (e.g., "004" for KBANK) |
description | string | No | Payment description (max 255 characters) |
metadata | object | No | Additional metadata (key-value pairs) |
idempotencyKey | string | No | Unique key to prevent duplicate payments (recommended) |
expiresInMinutes | number | No | Payment 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 processedrequires_payment_method- Payment method needs to be attachedrequires_confirmation- Payment needs to be confirmedrequires_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
| Code | Description |
|---|---|
VALIDATION_ERROR | Invalid request parameters |
INVALID_AMOUNT | Amount must be a valid decimal number |
INVALID_CURRENCY | Currency must be 'THB' |
INVALID_REFERENCE_ID | Reference ID format is invalid |
INVALID_BANK_CODE | Bank code must be a valid 3-digit Thai bank code |
DUPLICATE_REFERENCE_ID | Reference ID already exists for this merchant |
INVALID_CREDENTIALS | Authentication failed |
Related Endpoints
- Retrieve Payment - Get payment details
- List Payments - List all payments
- Cancel Payment - Cancel a payment
See Also
- Payment Methods
- Webhooks - Receive payment status updates
- Error Handling