Create VA
POST /openapi/v1/va/va-account/create
Create a Virtual Account (VA) for the Merchant to receive bank transfer payments.
Call Get Services first to obtain service_code (used as x-service-code header). Passing qr-pay will trigger the QR Pay creation flow.
Payload before encryption:
{
"request_id": "8bd13901-b0f1-42c1-b38f-59cd0d8faff8",
"bank_account_no": "31052426",
"internal_code": "KH_0000024",
"qr_type": "qrpay"
}
internal_codeis the Merchant CIF — it usually equals thePartner-Code(sandbox:KH_0000024), not a random number.va_typeis auto-assigned"M"forx-service-code="qr-pay";fixed_amountis optional (omit for a dynamic VA).
| Field | Required | Description |
|---|---|---|
request_id | ✅ | Unique identifier for each VA creation request |
bank_account_no | ✅ | Merchant's underlying bank account number |
internal_code | ✅ | Merchant CIF — the merchant's customer identifier at the bank (usually equals Partner-Code) |
va_type | ✕ | Virtual account type (optional, auto-assigned "M" when x-service-code="qr-pay") |
fixed_amount | ✕ | Fixed payment amount (if any) |
qr_type | ✕ | QR type ("qrpay" if QR Pay, default "ibft") |
- cURL
- Python
- Go
- JavaScript
curl --location '<base_url>/openapi/v1/va/va-account/create' \
--header 'Partner-Code: YOUR_PARTNER_CODE' \
--header 'x-service-code: SERVICE_CODE' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1…' \
--data '{
"data": ENCRYPTED_PAYLOAD
}'
import requests
url = "<base_url>/openapi/v1/va/va-account/create"
payload = {"data": "ENCRYPTED_PAYLOAD"}
headers = {
"Partner-Code": "YOUR_PARTNER_CODE",
"x-service-code": "SERVICE_CODE",
"Content-Type": "application/json",
"Authorization": "Bearer eyJhbGciOiJSUzI1…",
}
response = requests.post(url, headers=headers, json=payload)
print(response.text)
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
url := "<base_url>/openapi/v1/va/va-account/create"
body := strings.NewReader(`{"data":"ENCRYPTED_PAYLOAD"}`)
req, _ := http.NewRequest("POST", url, body)
req.Header.Set("Partner-Code", "YOUR_PARTNER_CODE")
req.Header.Set("x-service-code", "SERVICE_CODE")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer eyJhbGciOiJSUzI1…")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}
const response = await fetch("<base_url>/openapi/v1/va/va-account/create", {
method: "POST",
headers: {
"Partner-Code": "YOUR_PARTNER_CODE",
"x-service-code": "SERVICE_CODE",
"Content-Type": "application/json",
"Authorization": "Bearer eyJhbGciOiJSUzI1…",
},
body: JSON.stringify({ data: "ENCRYPTED_PAYLOAD" }),
});
const result = await response.text();
console.log(result);
Request
Headers
| Name | Required | Description |
|---|---|---|
Partner-Code | ✅ | Merchant identifier code (provided by TCONNECT) |
x-service-code | ✅ | Bank service code (from Get Services API). Passing qr-pay triggers QR Pay creation. |
Content-Type | ✅ | application/json |
Authorization | ✅ | Bearer <access_token> from Login |
Body
| Field | Type | Required | Description |
|---|---|---|---|
data | string | ✅ | AES-256-CBC encrypted payload as Hexadecimal |
Response
200 — VA created successfully
| Field | Type | Description |
|---|---|---|
va_account_no | string | Created virtual account number (e.g. VA100023312) |
request_id | string | Request ID |
ref_id | int | Virtual account reference ID |
[!NOTE] System Data & Storage Notes:
- Data sent to the processing system: Supplemented with
qr_type("qrpay"if QR Pay / default"ibft"),va_type(always set to"M"ifx-service-code="qr-pay"), andfixed_amount(if present).- MMS DB Storage (
res_partner_bank): Whenx-service-code="qr-pay", columnacc_typein DB is stored as'qr_pay'instead of'va', and duplicate VA/QR check query applies to both types.