ตั้ง Stripe Thailand + ออกใบกำกับภาษีอัตโนมัติ — คู่มือ SaaS ไทย
ลูกค้านิติบุคคลไทยต้องการ ใบกำกับภาษี สำหรับยื่น ภ.พ.30. ถ้า SaaS ของคุณออกให้ไม่ได้ → SME ไม่ซื้อ. ถ้าออกให้ → killer feature
ปัญหาที่ Thai SaaS เจอ
ลูกค้า SME ไทย: 'จ่ายค่า service ออกใบกำกับภาษียังไง'
ตัวเลือกที่มี:
- Foreign provider (Vercel/Heroku/Railway) → invoice ภาษาอังกฤษในนามต่างชาติ. ลูกค้าต้องไปยื่นกับสรรพากรเอง — เป็น hassle หรือ ทำไม่ได้สำหรับนิติบุคคล
- Thai provider เก่าๆ → ออกใบกำกับด้วยมือ ส่ง email หรือ snail mail. ช้า, error-prone, ไม่ scale
- DIY → integrate Stripe + Flowaccount/PEAK API เอง. 200-400 ชม. dev work
NirvaDeploy เลือก option 3 — แต่ทำให้ automated เป็น killer feature
Stack ที่ NirvaDeploy ใช้
┌─────────────────┐ Stripe THB ┌────────────────┐
│ Next.js App │ ──────────────▶ │ Stripe │
│ (web/) │ │ Thailand │
└─────────────────┘ └────────────────┘
│ │
│ webhook: invoice.payment_succeeded │
▼ │
┌─────────────────┐ Store Invoice row │
│ Webhook handler │ ──────────────────────▶ │
│ (Next.js API) │ Postgres (Prisma) │
└─────────────────┘ │
│ │
│ generate HTML invoice + email link │
▼ │
┌─────────────────┐ │
│ Internal │ ◀── ใบกำกับภาษี ภ.พ.30 │
│ HTML template │ (browser print→PDF) │
│ (own the plane) │ │
└─────────────────┘ │
│ │
└──── deliver to customer ──────┬─────┘
▼
📧 Customerทำไมสร้างเองแทนใช้ Flowaccount/PEAK:
- Zero dependency (ไม่ต้องซื้อ subscription 3rd party)
- Own the plane — เตรียมย้ายไป NirvaCore ERP ในอนาคต
- HTML → browser print-to-PDF = font Thai ทำงานเอง · searchable · portable
Stripe Thailand setup
1. สมัครบัญชี
ไปที่ stripe.com/th → Sign up
- Country: Thailand
- Business info: นิติบุคคลของคุณ (Best Investigation Co., Ltd. ของเราเป็นต้น)
- Tax ID: 13-digit เลขประจำตัวผู้เสียภาษี
2. ตั้ง currency เป็น THB
ทุก product ออก currency `thb` — ไม่ใช่ USD ที่ค่อย convert.
3. Enable PromptPay
ใน Stripe Dashboard → Settings → Payment methods → enable:
- ✅ Card (Visa, Mastercard, JCB, Amex)
- ✅ PromptPay (instant payment — Thai user love นี้)
- ⚠️ TrueMoney/ShopeePay (Phase 2.x — Stripe กำลังเพิ่ม)
4. Tax ID collection
// web/lib/stripe.ts (จาก NirvaDeploy source)
return stripe().checkout.sessions.create({
mode: "subscription",
payment_method_types: ["card", "promptpay"],
currency: "thb",
// ★ ขอข้อมูล tax ID ของลูกค้า — ถ้าเป็นนิติบุคคล
tax_id_collection: { enabled: true },
automatic_tax: { enabled: true },
invoice_creation: { enabled: true },
// ...
});tax_id_collection: enabled → checkout page จะมี optional field "ใส่ Tax ID" สำหรับลูกค้านิติบุคคล. automatic_tax: enabled → Stripe คำนวณ VAT 7% อัตโนมัติ (gross-inclusive)
ออกใบกำกับภาษีอัตโนมัติ
Stripe ออก default invoice — แต่ไม่ใช่ ภ.พ.30
Stripe สร้าง PDF invoice อยู่แล้ว แต่:
- ไม่มี Tax ID ผู้ขายไทย (ของคุณ)
- ไม่มี Tax ID ผู้ซื้อ (ของลูกค้า) ในตำแหน่งถูก
- ไม่เป็น format ที่สรรพากรไทยรับ
- ไม่ส่ง e-tax ให้กรมสรรพากรอัตโนมัติ
Solution: 2 ทางเลือก
ทางเลือก A — ใช้ 3rd party ERP (Flowaccount / PEAK / Xero)
- ✅ generate ให้ · ส่ง e-tax ให้กรมอัตโนมัติ
- ❌ เสีย ~฿400/mo subscription · vendor lock · ต้องต่อ API เพิ่ม
ทางเลือก B — สร้างเอง (NirvaDeploy เลือกทางนี้) ⭐
- ✅ Zero external dep · own the plane · migrate ไป NirvaCore (ERP ของเรา) ได้ในอนาคต
- ✅ HTML page + browser print-to-PDF = font Thai ทำงานเอง · searchable · portable
- ❌ ต้องเขียน template + numbering + PDF logic เอง (~200 บรรทัด)
Data model แบบ vendor-neutral (ใช้ได้ทั้งสองทาง):
// web/lib/invoice.ts (จาก NirvaDeploy source)
export type InvoicePayload = {
invoiceNumber: string;
issueDate: string;
customerName: string;
customerTaxId?: string;
customerAddress?: string;
items: InvoiceItem[];
};
export function toInvoiceJson(payload, calc) {
return {
seller: {
taxId: "0405538000091", // ★ ของคุณ — Tax ID 13 digits
name: "Best Investigation Co., Ltd.",
},
customer: {
name: payload.customerName,
taxId: payload.customerTaxId, // จาก Stripe tax_id_collection
address: payload.customerAddress, // จาก Stripe billing address
},
invoice: {
number: payload.invoiceNumber,
issueDate: payload.issueDate,
type: "TAX_INVOICE", // ใบกำกับภาษี
items: payload.items,
subtotal: calc.subtotalTHB,
vat: calc.vatTHB, // 7%
vatRate: 0.07,
total: calc.totalTHB,
currency: "THB",
},
};
}ทีม NirvaDeploy เลือกทางเลือก B (สร้างเอง) เพราะ NirvaCore ERP ในอนาคต จะ consume payload นี้ตรง ๆ · ไม่ต้อง rewrite
Webhook handler
// web/app/api/billing/webhook/route.ts (จาก NirvaDeploy source)
export async function POST(req: NextRequest) {
const signature = req.headers.get("stripe-signature");
const body = await req.text();
const event = stripe().webhooks.constructEvent(body, signature, STRIPE_WEBHOOK_SECRET);
if (event.type === "invoice.payment_succeeded") {
const invoice = event.data.object;
const customer = await stripe().customers.retrieve(invoice.customer);
// Generate running invoice number
const invoiceNumber = nextInvoiceNumber(seq); // "INV-2026-05-0042"
// Calc VAT
const items = invoice.lines.data.map((line) => ({
description: line.description,
quantity: line.quantity,
unitPriceTHB: line.amount / 100 / line.quantity, // Stripe stores in satang
}));
const calc = calculateInvoice(items);
// Build canonical invoice JSON (vendor-neutral)
const payload = toInvoiceJson({
invoiceNumber,
issueDate: new Date().toISOString().slice(0, 10),
customerName: customer.name,
customerTaxId: customer.tax_ids?.data[0]?.value,
customerAddress: customer.address?.line1,
items,
}, calc);
// Store in DB (view via /api/billing/invoice/[id] → HTML → browser print-to-PDF)
await prisma.invoice.create({ data: { ...payload.invoice, userId: user.id } });
// Email link ให้ลูกค้า (view page มี Cmd+P → PDF)
await sendInvoiceReceipt({ user, invoice: payload.invoice, baseUrl });
}
return NextResponse.json({ received: true });
}Edge cases ที่ต้องเตรียม
Customer ไม่ใส่ Tax ID
ออกเป็น ใบเสร็จรับเงิน (Receipt) แทน ใบกำกับภาษี — สำหรับบุคคลธรรมดา.
const isCorporate = !!customer.tax_ids?.data[0]?.value;
const invoiceType = isCorporate ? "TAX_INVOICE" : "RECEIPT";Refund / partial refund
PDPA + Thai tax law: ออก ใบลดหนี้ (Credit Note) แทน edit เดิม.
if (event.type === "charge.refunded") {
// Generate credit note (own the plane · same internal template)
const creditNote = {
type: "CREDIT_NOTE",
referencesInvoiceNumber: invoiceNumber,
reason: "Refund processed",
items: [...], // negative quantities
};
}Annual / one-time payment
Stripe webhook ก็ส่ง invoice.payment_succeeded เหมือนกัน — code path เดียวกัน.
Cost analysis
Stripe Thailand fees
- 3.65% + ฿11 per transaction (card)
- 1.65% per transaction (PromptPay) — ถูกกว่า card 2%
- No monthly fee
Invoice generation — ค่าใช้จ่ายเทียบ
| ทางเลือก | ต้นทุน/เดือน | หมายเหตุ |
|---|---|---|
| Flowaccount API Standard | ฿590 (1,000 ใบ) | vendor lock · ต้องต่อ API |
| Flowaccount API Pro | ฿1,290 (5,000 ใบ) | เพิ่ม 5x เพดาน |
| NirvaDeploy internal (สร้างเอง) ⭐ | ฿0 | one-time dev · own the plane |
NirvaDeploy เลือก internal — ประหยัด · migrate ไป NirvaCore ERP ในอนาคตได้
Total cost @ 100 paying users × ฿333 Pro tier (Karma baseline)
- Revenue: 100 × ฿333 = ฿33,300/mo
- Stripe fees: 100 × (333 × 3.65% + 11) = ~฿2,320/mo (card avg)
- Flowaccount: ฿590/mo
- Net: ~฿30,390/mo (~91% retention)
ทำไม NirvaDeploy ดูแลเรื่องนี้ให้
NirvaDeploy = PaaS ไทย — ออกใบกำกับภาษีในนาม Best Investigation Co., Ltd. ให้ลูกค้าอัตโนมัติ. คุณ subscribe Pro ฿333 (baseline) → ได้ ภ.พ.30 ภายใน 24 ชม.
ถ้าคุณ build Thai SaaS เอง — copy pattern จาก NirvaDeploy source code ได้ (MIT license หลัง Phase 2 launch)
Resources
- Stripe Thailand docs: stripe.com/docs/payments/payment-methods/thailand
- Flowaccount API: flowaccount.com/api
- PEAK accounting API: peakaccount.com/api-docs
- e-Tax Thailand spec: กรมสรรพากร e-Tax
NirvaDeploy source code references
- `web/lib/stripe.ts` — Stripe singleton + tier config + checkout session
- `web/lib/invoice.ts` — VAT calc + Flowaccount payload
- `web/app/api/billing/webhook/route.ts` — webhook handler
คำถาม Stripe Thailand + ใบกำกับภาษี? Email [email protected] — เรา reply ปกติใน 4-12 ชม.
ชอบบทความนี้?
ลอง NirvaDeploy ฟรี
Free tier ตลอดชีพ · ไม่ต้องใส่บัตร · Sign in ด้วย Line/Google
เริ่มเลย →