POST /qr/generate
Generate PromptPay and merchant QR codes for receiving payments.
Endpoint
POST /qr/generateFull URL: https://api.thunder.in.th/v1/qr/generate
v1 Only
QR code generation is only available in API v1.
Authentication
Required. See Authentication Guide.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/jsonRequest
QR Types
| Type | Description |
|---|---|
PROMPTPAY | Personal PromptPay QR code |
KSHOP | Kasikorn K-Shop merchant QR code |
MAE_MANEE | Mae Manee merchant QR code |
TUNGNGERN | Tungngern merchant QR code |
BILL_PAYMENT | Bill payment QR with your registered Biller ID (Tag 30) |
Type Definitions
// Request Types
type QRGenerateRequest =
| PromptPayRequest
| KShopRequest
| MaeManeeRequest
| TungngernRequest | BillPaymentRequest;
interface BillPaymentRequest {
type: 'BILL_PAYMENT';
billerId: string; // 15 digits, including the suffix; preserve leading zeroes
ref1: string; // 1-20 printable ASCII characters, case preserved
ref2?: string; // Same format as ref1; omit when unused
amount?: number; // 0.01 to 9999999999.99, at most 2 decimals
}
interface PromptPayRequest {
type: 'PROMPTPAY';
msisdn?: string; // Mobile number (0xxxxxxxxx)
natId?: string; // National ID (13 digits)
eWalletId?: string; // E-wallet ID (15 digits)
amount?: number; // Amount (max 2 decimals)
}
interface KShopRequest {
type: 'KSHOP';
ref1: string; // Reference 1 (1-20 alphanumeric, uppercase)
amount?: number;
}
interface MaeManeeRequest {
type: 'MAE_MANEE';
ref1: string; // Reference 1 (1-20 alphanumeric, uppercase)
amount?: number;
}
interface TungngernRequest {
type: 'TUNGNGERN';
ref1: string; // Reference 1 (1-20 alphanumeric, uppercase)
merchantName?: string; // Merchant name (1-25 characters)
amount?: number;
}
// Response
interface QRGenerateResponse {
status: 200;
data: QRData;
}
interface QRData {
image: string; // Base64-encoded PNG image
mime: string; // MIME type (image/png)
payload: string; // QR code payload string
}
// Error Response
interface ErrorResponse {
status: number;
message: string;
details?: string | Array<{ field: string; message: string }>;
}Examples
Bill Payment (Biller ID)
Use a 15-digit Biller ID registered with your bank or payment provider. This endpoint generates a payment QR; it does not issue or register a Biller ID, or check whether that ID is active.
{
"type": "BILL_PAYMENT",
"billerId": "010555123456701",
"ref1": "INV20261014001",
"ref2": "CUSTOMER001",
"amount": 125.50
}The example ID is illustrative; replace it with your own registered Biller ID.
| Field | Required | Format |
|---|---|---|
billerId | Yes | String of exactly 15 digits including the suffix; leading zeroes preserved |
ref1 | Yes | 1-20 printable ASCII characters; not whitespace-only |
ref2 | No | Same format as ref1; omit when unused |
amount | No | Positive number, at most 2 decimals, maximum 9999999999.99 THB |
References are preserved exactly, including case and spaces. Use the reference format required by your bank for your Biller ID. Omitting amount lets the payer enter it. The response (image, mime, payload) is unchanged from the existing QR types.
Payload structure follows the Bank of Thailand Thai QR Code standard, page 15.
PromptPay
curl -X POST https://api.thunder.in.th/v1/qr/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "PROMPTPAY",
"msisdn": "0812345678",
"amount": 100.00
}'const generateQR = async (config) => {
const response = await fetch('https://api.thunder.in.th/v1/qr/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(config)
});
const result = await response.json();
if (result.status !== 200) {
throw new Error(result.message);
}
return result.data;
};
// Generate PromptPay QR
const qr = await generateQR({
type: 'PROMPTPAY',
msisdn: '0812345678',
amount: 100.00
});
// Display QR code
const img = document.createElement('img');
img.src = `data:${qr.mime};base64,${qr.image}`;
document.body.appendChild(img);function generateQR(array $config): array
{
$apiKey = getenv('THUNDER_API_KEY');
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.thunder.in.th/v1/qr/generate',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode($config)
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['status'] !== 200) {
throw new Exception($result['message']);
}
return $result['data'];
}
// Generate PromptPay QR
$qr = generateQR([
'type' => 'PROMPTPAY',
'msisdn' => '0812345678',
'amount' => 100.00
]);
// Save as file
$imageData = base64_decode($qr['image']);
file_put_contents('qr-code.png', $imageData);
// Or display inline
echo '<img src="data:' . $qr['mime'] . ';base64,' . $qr['image'] . '">';import requests
import base64
import os
def generate_qr(config: dict) -> dict:
response = requests.post(
'https://api.thunder.in.th/v1/qr/generate',
headers={
'Authorization': f'Bearer {os.environ["THUNDER_API_KEY"]}',
'Content-Type': 'application/json'
},
json=config
)
result = response.json()
if result['status'] != 200:
raise Exception(result['message'])
return result['data']
# Generate PromptPay QR
qr = generate_qr({
'type': 'PROMPTPAY',
'msisdn': '0812345678',
'amount': 100.00
})
# Save as file
image_data = base64.b64decode(qr['image'])
with open('qr-code.png', 'wb') as f:
f.write(image_data)
print(f"Payload: {qr['payload']}")K-Shop
{
"type": "KSHOP",
"ref1": "ORDER12345",
"amount": 250.00
}Mae Manee
{
"type": "MAE_MANEE",
"ref1": "ORDER12345",
"amount": 500.00
}Tungngern
{
"type": "TUNGNGERN",
"ref1": "ORDER12345",
"merchantName": "MY STORE",
"amount": 750.00
}Response
Success (200)
{
"status": 200,
"data": {
"image": "iVBORw0KGgoAAAANSUhEUgAA...",
"mime": "image/png",
"payload": "00020101021230..."
}
}Response Fields
| Field | Type | Description |
|---|---|---|
image | string | Base64-encoded PNG image |
mime | string | MIME type (image/png) |
payload | string | QR code payload string |
Error Responses
Invalid Request (400)
{
"status": 400,
"message": "invalid_request",
"details": [
{ "field": "ref1", "message": "Required" }
]
}Unauthorized (401)
{
"status": 401,
"message": "unauthorized"
}Parameter Reference
PromptPay
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | "PROMPTPAY" |
msisdn | string | One of | Mobile number (0xxxxxxxxx) |
natId | string | One of | National ID (13 digits) |
eWalletId | string | One of | E-wallet ID (15 digits) |
amount | number | No | Amount (max 2 decimals) |
TIP
You must provide exactly one of: msisdn, natId, or eWalletId.
K-Shop
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | "KSHOP" |
ref1 | string | Yes | Reference 1 (1-20 alphanumeric, uppercase) |
amount | number | No | Amount (max 2 decimals) |
Mae Manee
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | "MAE_MANEE" |
ref1 | string | Yes | Reference 1 (1-20 alphanumeric, uppercase) |
amount | number | No | Amount (max 2 decimals) |
Tungngern
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | "TUNGNGERN" |
ref1 | string | Yes | Reference 1 (1-20 alphanumeric, uppercase) |
merchantName | string | No | Merchant name (1-25 characters) |
amount | number | No | Amount (max 2 decimals) |
Notes
- QR code generation does not consume verification quota
- Generated QR codes are valid indefinitely
- Amount is optional - customer can enter amount when paying
- KSHOP, MAE_MANEE and TUNGNGERN ref1 fields are alphanumeric and normalized to uppercase. BILL_PAYMENT references preserve case and support printable ASCII.
