| name | thai-id-validate |
| description | Use this skill for any task involving Thai national ID, tax ID, phone number, or PromptPay QR code validation, normalization, or generation. Trigger whenever the user asks to: validate a Thai citizen ID, check a tax ID checksum, normalize Thai phone numbers between +66 and 0X formats, or build a PromptPay QR payload. Also trigger for requests like "āļāļĢāļ§āļāđāļĨāļāļāļąāļāļĢāļāļĢāļ°āļāļēāļāļ", "āđāļāđāļāđāļĨāļāļāļđāđāđāļŠāļĩāļĒāļ āļēāļĐāļĩ", "āđāļāļĨāļāđāļāļāļĢāđāđāļāļĢ +66", "āļŠāļĢāđāļēāļ PromptPay QR", "āļāļģāļāļīāļ§āļāļēāļĢāđāļāļĢāđāļāļĄāđāļāļĒāđ", or any variation involving 13-digit Thai IDs or Thai phone formats. |
Thai ID / Phone / PromptPay (āļāļĢāļ§āļāđāļĨāļāļāļąāļāļĢ āđāļāļāļĢāđ āļāļĢāđāļāļĄāđāļāļĒāđ)
Overview
āļāļĢāļ§āļāļŠāļāļ checksum āļāļāļāđāļĨāļāļāļąāļāļĢāļāļĢāļ°āļāļēāļāļāđāļāļĒ / āđāļĨāļāļāļĢāļ°āļāļģāļāļąāļ§āļāļđāđāđāļŠāļĩāļĒāļ āļēāļĐāļĩ (13 āļŦāļĨāļąāļ), āđāļāļĨāļāđāļāļāļĢāđāđāļāļĢāļĢāļ°āļŦāļ§āđāļēāļāļĢāļđāļ +66 āļāļąāļ 0X, āđāļĨāļ°āļŠāļĢāđāļēāļ payload āļŠāļģāļŦāļĢāļąāļ PromptPay QR (āļĢāļđāļāđāļāļ EMVCo TLV). Algorithm and TLV layout follow the official Thai Revenue Department and ITMX PromptPay specifications.
When to use
- āļāļĢāļ§āļ checksum āđāļĨāļāļāļąāļāļĢāļāļĢāļ°āļāļēāļāļ 13 āļŦāļĨāļąāļ (citizen ID / individual tax ID share the same algorithm)
- Normalize āđāļāļāļĢāđāđāļāļĢ: āļāļđāđāđāļāđāļāđāļāļ
+66 81 234 5678 āđāļāđāļĢāļ°āļāļāđāļāđāļ 0812345678
- āļŠāļĢāđāļēāļ QR āļŠāļģāļŦāļĢāļąāļāļĢāļąāļāđāļāļīāļ PromptPay āļāļēāļāđāļāļāļĢāđāļĄāļ·āļāļāļ·āļāļŦāļĢāļ·āļāđāļĨāļāļāļąāļāļĢāļāļĢāļ°āļāļēāļāļ
- DO NOT use for company tax IDs that follow non-standard formats, or for verifying that an ID belongs to a real person (checksum only proves format, not existence).
Example prompts
- "āļāļĢāļ§āļāđāļĨāļāļāļąāļāļĢ 1-1017-00230-70-X āđāļŦāđāļŦāļāđāļāļĒ"
- "āđāļāļāļĢāđ 081-234-5678 āđāļāļĨāļāđāļāđāļ E.164 āđāļŦāđāļāļĩ"
- "āļŠāļĢāđāļēāļ PromptPay QR āđāļāļāļĢāđ 0812345678 āļāļģāļāļ§āļ 250 āļāļēāļ"
Quick reference
| Function | āļ āļēāļĐāļēāđāļāļĒ | Returns |
|---|
is_valid_thai_id(s) | āļāļĢāļ§āļ checksum | bool |
normalize_phone(s) | āđāļāļĨāļāđāļāđāļ +66XXXXXXXXX | str |
format_phone_thai(s) | āđāļāļĨāļāđāļāđāļ 0XX-XXX-XXXX | str |
build_promptpay_payload(target, amount?) | āļŠāļĢāđāļēāļ QR payload | str |
Thai ID checksum algorithm
āđāļŦāđāļāļąāļ§āđāļĨāļ 12 āļŦāļĨāļąāļāđāļĢāļ āļāļđāļāļāđāļ§āļĒāļāđāļģāļŦāļāļąāļ [13,12,11,10,9,8,7,6,5,4,3,2] āđāļĨāđāļ§āļĢāļ§āļĄāļāļąāļ. āļāļģāļāļĨāļĢāļ§āļĄ mod 11, āđāļāļē 11 āļĨāļ, āđāļĨāđāļ§ mod 10 āļāļĩāļāļāļĢāļąāđāļ = check digit (āļŦāļĨāļąāļāļāļĩāđ 13).
Phone format rules
- āļŦāļĨāļąāļāļāļēāļ strip āđāļāļĢāļ·āđāļāļāļŦāļĄāļēāļĒāđāļ§āđāļāļ§āļĢāļĢāļ
- () āđāļĨāđāļ§
- āļāļķāđāļāļāđāļ
+66, 66, āļŦāļĢāļ·āļ 0 āļāļ·āļāļ§āđāļēāđāļāļĩāļĒāļāđāļāđāļēāļāļąāļ
- āļĄāļ·āļāļāļ·āļ: 10 āļŦāļĨāļąāļāļĢāļ§āļĄ 0 (06, 08, 09 āļŦāļĨāļąāļāļāļēāļ 0)
- āļāđāļēāļ Bangkok: 9 āļŦāļĨāļąāļāļĢāļ§āļĄ 0 (āđāļāđāļ 02-880-1234)
PromptPay TLV (key tags)
00 Payload Format Indicator 01
01 POI Method: 11 static / 12 dynamic (with amount)
29 Merchant Account Info â sub-tag 00 AID A000000677010111, sub-tag 01 phone (0066 + āđāļāļāļĢāđ, pad to 13 chars) or 02 national ID (13 digits)
53 Currency 764 (THB)
54 Amount (optional)
58 Country TH
63 CRC-16/CCITT-FALSE (uppercase 4-hex) over the entire payload including the 6304 tag/length prefix
Implementation
- Python:
validate.py â python validate.py runs all self-tests
- TypeScript:
validate.ts â npx tsx validate.ts runs all self-tests
āđāļĨāļāļŦāļĨāļąāļāđāļĢāļāļāļāļāļāļąāļāļĢāļāļĢāļ°āļāļēāļāļ (First-digit prefix)
āļŦāļĨāļąāļāđāļĢāļāļāļāļāđāļĨāļ 13 āļŦāļĨāļąāļāļāļāļ āļāļĢāļ°āđāļ āļ āļāļāļāļāļđāđāļāļ·āļāļāļąāļāļĢāļāļēāļĄāļāļĩāđāļāļĢāļĄāļāļēāļĢāļāļāļāļĢāļāļ (DOPA) āļāļģāļŦāļāļ āļĄāļĩ 8 āļāļĢāļ°āđāļ āļāļŦāļĨāļąāļ:
| āļŦāļĨāļąāļāđāļĢāļ | āļāļ§āļēāļĄāļŦāļĄāļēāļĒ (TH) | Meaning (EN) |
|---|
| 1 | āļŠāļąāļāļāļēāļāļīāđāļāļĒ āđāļāļīāļāđāļĨāļ°āđāļāđāļāđāļāļīāļāļāļēāļĄāļāļģāļŦāļāļ āļāļąāđāļāđāļāđ 1 āļĄ.āļ. 2527 | Thai citizen born âĨ 1 Jan 1984 with timely birth registration |
| 2 | āļŠāļąāļāļāļēāļāļīāđāļāļĒ āđāļāļīāļāđāļĨāļ°āđāļāđāļāđāļāļīāļāđāļāļīāļāļāļģāļŦāļāļ āļāļąāđāļāđāļāđ 1 āļĄ.āļ. 2527 | Thai citizen born âĨ 1984 with late birth registration |
| 3 | āļŠāļąāļāļāļēāļāļīāđāļāļĒ āļĄāļĩāļāļ·āđāļāđāļāļāļ°āđāļāļĩāļĒāļāļāđāļēāļāļāđāļāļ 1 āļĄ.āļ. 2527 | Thai citizen already in household registry before 1984 |
| 4 | āļŠāļąāļāļāļēāļāļīāđāļāļĒ āđāļĄāđāļĄāļĩāļāļ·āđāļāđāļāļāļ°āđāļāļĩāļĒāļāļāđāļēāļāļāđāļāļ 1 āļĄ.āļ. 2527 (āđāļāļīāđāļĄāļāļ·āđāļāļāđāļ§āļāļŠāļģāļĢāļ§āļ) | Thai citizen not in the initial pre-1984 registry |
| 5 | āļŠāļąāļāļāļēāļāļīāđāļāļĒ āđāļāļīāđāļĄāļāļ·āđāļāđāļāđāļēāļāļ°āđāļāļĩāļĒāļāļāđāļēāļāļ āļēāļĒāļŦāļĨāļąāļ (āļĢāļ§āļĄāđāļāđāļāđāļāļīāļāđāļāļīāļāļāļģāļŦāļāļāđāļĨāļ°āļāļĢāļāļĩāļāļĨāļąāļāļāļ·āļāļŠāļąāļāļāļēāļāļī) | Thai citizen added to registry later (incl. late birth & re-recognition) |
| 6 | āļāļļāļāļāļĨāļāļĩāđāđāļāđāļēāđāļĄāļ·āļāļāđāļāļĒāļāļāļāļāđāļ§āļĒāļāļāļŦāļĄāļēāļĒāļāļąāđāļ§āļāļĢāļēāļ§ / āļāļđāđāļāļĨāļąāļāļāļīāđāļ / āļāļāļāļĨāļļāđāļĄāļāđāļāļĒ | Lawful temporary resident, displaced person, or ethnic minority awaiting status |
| 7 | āļāļļāļāļĢāļāļāļāļāļļāļāļāļĨāļāļĢāļ°āđāļ āļ 6 āļāļĩāđāđāļāļīāļāđāļāļāļĢāļ°āđāļāļĻāđāļāļĒ | Children of category-6 persons, born in Thailand |
| 8 | āļāļļāļāļāļĨāļāđāļēāļāļāđāļēāļ§āļāļĩāđāđāļāđāļĢāļąāļāļŠāļąāļāļāļēāļāļīāđāļāļĒ / āļĄāļĩāļāļīāđāļāļāļĩāđāļāļĒāļđāđāļāļēāļ§āļĢ | Naturalized Thai citizen or permanent-residence holder |
āļŦāļĄāļēāļĒāđāļŦāļāļļ: āļŦāļĨāļąāļāđāļĢāļ 0 āđāļāļĒāđāļāđāļāļąāļāļāļĢāļāļĩāļāļīāđāļĻāļĐāļāļēāļāļāļĒāđāļēāļāđāļāļāļāļĩāļ āđāļāđāļāļāđāļāđāļāđāļāļĒāļĄāļēāļāđāļāļĢāļ°āļāļāļāļąāļāļāļļāļāļąāļ. āđāļāđāļŠāļģāļŦāļĢāļąāļāļāļēāļ HR/KYC āđāļāļ·āđāļāđāļāđāļēāđāļ background āļāļāļāļāļđāđāļŠāļĄāļąāļāļĢ â āļŦāđāļēāļĄ āđāļāđāļŦāļĨāļąāļāđāļĢāļāđāļāļĩāļĒāļāļāļĒāđāļēāļāđāļāļĩāļĒāļ§āđāļāđāļāđāļāļāļāđāđāļĨāļ·āļāļāļāļāļīāļāļąāļāļī (āđāļāđāļ āļāļāļīāđāļŠāļāļĢāļąāļāļŠāļĄāļąāļāļĢāļāļēāļāđāļāļĢāļēāļ°āļŦāļĨāļąāļāđāļĢāļāđāļĄāđāđāļāđ 1â5) āđāļāļĢāļēāļ°āļāļīāļāļāļąāđāļāļāļāļŦāļĄāļēāļĒāđāļĢāļāļāļēāļāđāļĨāļ°āđāļĄāđāļāļĢāļāđāļāļāļāļēāļāļāļāļĢāļ°āļāļāđāļĨāļāļāļĢāļ°āļāļģāļāļąāļ§.
Slip QR (QR āļāļāļŠāļĨāļīāļāđāļāļāđāļāļīāļ)
āđāļāļāļāļāļēāļāļēāļĢāđāļāļĒāļĒāļļāļāđāļŦāļĄāđāļāļąāļ QR code āđāļ§āđāļāļāļŠāļĨāļīāļāđāļāļāđāļāļīāļāļāļļāļāđāļ āđāļāļ·āđāļāđāļŦāđāļāļđāđāļĢāļąāļāđāļāļīāļ āļĒāļ·āļāļĒāļąāļāļŠāļĨāļīāļāđāļāđāļāļĢāļīāļ āđāļāļāļāļĩāđāļāļ°āđāļāļ·āđāļāļ āļēāļ JPG āļāļĩāđāļāļēāļāļāļđāļāļāļąāļāļāđāļ.
āđāļāļĢāļāļŠāļĢāđāļēāļ payload. āđāļāđāļ EMVCo TLV (āļĢāļđāļāđāļāļāđāļāļĩāļĒāļ§āļāļąāļ PromptPay payment QR) āđāļāđāđāļāđāļ āļāļāļĨāļ° profile â āđāļāđāļāļāđāļāļĄāļđāļĨāļāļļāļĢāļāļĢāļĢāļĄāđāļāļāļāđāļāļĄāļđāļĨāļāļđāđāļĢāļąāļāđāļāļīāļ. āļāļīāļĨāļāđāļāļąāđāļ§āđāļāļāļĩāđāļāļĒāļđāđāđāļ TLV āļāļāļāļŠāļĨāļīāļ:
- Payload format indicator + POI method (āđāļāđāļāđāļāļĩāļĒāļ§āļāļąāļ PromptPay)
- āļĢāļŦāļąāļŠāļāļāļēāļāļēāļĢāļāļđāđāļŠāđāļ (sending bank ID, 3 āļŦāļĨāļąāļāļāļēāļĄāļĢāļŦāļąāļŠ BOT)
- āļĢāļŦāļąāļŠāļāļāļēāļāļēāļĢāļāļđāđāļĢāļąāļ (receiving bank ID)
- āđāļĨāļāļāđāļēāļāļāļīāļāļāļļāļĢāļāļĢāļĢāļĄ (transaction reference ID â āļĢāļŦāļąāļŠāđāļāļāļēāļ°āļāļĩāđāļāļāļēāļāļēāļĢāļāļđāđāļŠāđāļāļāļāļāđāļŦāđ)
- āļāļģāļāļ§āļāđāļāļīāļ, āļŠāļāļļāļĨāđāļāļīāļ (
764), country (TH)
- timestamp āļāļāļāļāļēāļĢāđāļāļ
- CRC-16/CCITT-FALSE āļāļīāļāļāđāļēāļĒ
āļāļēāļĢāļĒāļ·āļāļĒāļąāļ. āđāļĄāļ·āđāļāļŠāđāļāļ QR āļāļāļŠāļĨāļīāļ āđāļāļāļāļāļēāļāļēāļĢāļāļ°āļāļķāļ (sending_bank_id, transaction_ref_id) āļāļāļāļāļēāļ payload āđāļĨāđāļ§āļĒāļīāļ API āļāļāļāļāļāļēāļāļēāļĢāļāļđāđāļāļāļāļŠāļĨāļīāļ (āđāļāđāļ KBank Slip Verification API, SCB Slip Verify) āđāļāļ·āđāļāļāļāļāđāļāļĄāļđāļĨāļāļļāļĢāļāļĢāļĢāļĄāļāļĢāļīāļāļāļĨāļąāļāļĄāļēāđāļāļĩāļĒāļ. āļāđāļēāļāļāļēāļāļēāļĢāļāļāļāļāļĨāļąāļāļ§āđāļē "āđāļĄāđāļāļāļāļļāļĢāļāļĢāļĢāļĄ" āļŦāļĢāļ·āļāļāļģāļāļ§āļāđāļāļīāļāđāļĄāđāļāļĢāļ = āļŠāļĨāļīāļāļāļĨāļāļĄ.
āđāļŦāļāļļāļāļĨāļāļĩāđāļĄāļĩ. āļāļąāļāļāļēāļĢāļāļĨāļāļĄāļŠāļĨāļīāļāļāđāļ§āļĒāļāļēāļĢāđāļāđāļ āļēāļ â āļ āļēāļāļŠāļĨāļīāļāļāļĨāļāļĄāļāļģāđāļāđāļāđāļēāļĒāļĄāļēāļ (āđāļāđ Photoshop) āđāļāđ QR āļāļĨāļāļĄāđāļĄāđāđāļāđāđāļāļĢāļēāļ°āļāđāļāļĄāļđāļĨāļāļđāļ validate āļāļĩāđāļāļąāđāļ server āļāļāļāļāļāļēāļāļēāļĢāļāļđāđāļāļāļāļŠāļĨāļīāļ āđāļĄāđāđāļāđāđāļāļāļąāļ§ QR āđāļāļ. āļāļđāđāļāđāļēāļĢāļēāļĒāļĒāđāļāļĒāļāļĩāđāļĢāļąāļāđāļāļ PromptPay āļāļ§āļĢāļŠāđāļāļ QR āļāļāļŠāļĨāļīāļāļĨāļđāļāļāđāļēāļāđāļāļāļāļĨāđāļāļĒāļāļāļ āđāļĄāđāđāļāđāļāļđāđāļāđāļ āļēāļ.
Known gap. validate.py / validate.ts āđāļāļŠāļāļīāļĨāļāļĩāđ āđāļĄāđ parse slip QR â āļĢāļāļāļĢāļąāļāđāļāļāļēāļ°āļāļēāļĢ āļŠāļĢāđāļēāļ PromptPay payment payload āđāļāđāļēāļāļąāđāļ. āļāđāļēāļāđāļāļāļāļēāļĢ parse/verify āļŠāļĨāļīāļāļāļĢāļīāļ āđāļāđāđāļĨāļāļĢāļēāļĢāļĩāđāļāļāļēāļ°āļāļēāļ (āđāļāđāļ slipverify, thanakan) āļāļĩāđāđāļĢāļĩāļĒāļ API āļāļāļēāļāļēāļĢāļāļđāđāļāļāļāļŠāļĨāļīāļāđāļāđ.
Common mistakes
- Hardcoded fake fixtures. Don't paste a random 13-digit string and assume it passes. Build fixtures by computing the check digit from a 12-digit prefix.
- Forgetting the
% 10 step. When total % 11 == 0, 11 - 0 = 11. Mod 10 yields 1, not 11.
- PromptPay CRC scope. The CRC is computed over the entire payload up to and including the literal
"6304" tag+length, not just the body before tag 63.
- Phone digit count. Bangkok landlines are 9 digits (incl. leading 0); mobiles are 10. If you assume 10 always you'll mis-validate landlines.
- Tax ID vs corporate ID. Individual tax ID == citizen ID checksum. Juristic-person (company) tax IDs are a different 13-digit allocation but use the same checksum, so the same function validates both.
- Trusting the first digit as proof of nationality. āļŦāļĨāļąāļāđāļĢāļ = 1â5 āļāđāļāļāļāļāļ§āđāļē āļĢāļ°āļāļāļāļ°āđāļāļĩāļĒāļ āļāļąāļāđāļāđāļāļŠāļąāļāļāļēāļāļīāđāļāļĒ āļ āđāļ§āļĨāļēāļāļāļāđāļĨāļ â āđāļĄāđāđāļāđāļŦāļĨāļąāļāļāļēāļāļŠāļąāļāļāļēāļāļīāļāļąāļāļāļļāļāļąāļ. āļāļĢāļ§āļāļāļąāļāđāļāļāļŠāļēāļĢāļāļĢāļīāļ (āļāļąāļāļĢāļāļĢāļ°āļāļēāļāļ, āļāļ°āđāļāļĩāļĒāļāļāđāļēāļ) āđāļŠāļĄāļ. āđāļĨāļ°āļāļĒāđāļēāđāļāđāļŦāļĨāļąāļāđāļĢāļāđāļāđāļāđāļāļ·āđāļāļāđāļāļāļĢāļāļāļāļđāđāļŠāļĄāļąāļāļĢ â āļāļīāļāđāļāļāļāļēāđāļĨāļ°āļāļēāļāđāļāđāļēāļāđāļēāļĒāđāļĨāļ·āļāļāļāļāļīāļāļąāļāļī.
- Accepting a slip JPG as payment proof without QR verification. āļ āļēāļāļŠāļĨāļīāļāļāļĨāļāļĄāļāđāļēāļĒāļĄāļēāļ. āļāđāļēāļĢāļąāļāđāļāļāđāļāļīāļāļāļĢāļīāļāļāļąāļ āļāđāļāļāļŠāđāļāļ QR āļāļāļŠāļĨāļīāļāđāļĨāđāļ§āđāļŦāđāđāļāļāļāļāļēāļāļēāļĢ verify āļāļąāļ server āļāļāļāļāļāļēāļāļēāļĢāļāļđāđāļāļāļ â āļāļĒāđāļēāđāļāļ·āđāļāđāļāđāļāļąāļ§āđāļĨāļāđāļāļĢāļđāļ.