Tích hợp thanh toán với Claude Code: Stripe + Sepay từ A-Z (2026)
Bạn có thể dùng Claude Code để dựng luồng thanh toán thật cho app Next.js/Node: chọn cổng (Stripe cho khách quốc tế, Sepay/VietQR cho khách Việt Nam), rồi để Claude Code đọc repo, sinh route checkout và webhook handler, cuối cùng bạn test và review. Năm bước lõi: chọn cổng → brief Claude Code kèm CLAUDE.md → tạo checkout → viết webhook idempotent → test và bảo mật. Vì đụng tiền nên con người luôn phải review, đừng để agent tự chạy lệnh production.
Vì sao dùng Claude Code để tích hợp thanh toán?
Tích hợp thanh toán là loại việc lặp đi lặp lại nhưng dễ sai: tạo route checkout, xử lý redirect, viết webhook, verify chữ ký, lưu đơn, test đủ ca. Làm tay theo docs thì mất buổi, mà bỏ sót một chi tiết (ví dụ webhook không idempotent) là double-charge như chơi.
Điểm mạnh của Claude Code ở đây là nó đóng vai người dựng, không chỉ gợi ý code. Trong một phiên, nó đọc cấu trúc repo của bạn, hiểu bạn đang dùng App Router hay Express, rồi sinh đúng route API, sinh webhook handler khớp payload của cổng, và chạy được lệnh test ngay tại terminal. Việc rút từ "vài giờ mò docs" xuống "vài phút review diff" là khác biệt thật, nhất là khi bạn phải làm cả hai cổng Stripe và Sepay cùng lúc. Nếu chưa quen để Claude Code viết API, đọc trước bài dùng Claude Code viết API backend để nắm cách brief đúng.
Nhưng phải nói thẳng ngay từ đầu: thanh toán đụng tiền thật, nên con người vẫn phải review từng dòng. Claude Code có thể verify sai đơn vị tiền tệ, quên một nhánh edge case, hoặc đề xuất API cũ. Xem nó là một dev junior nhanh tay - bạn vẫn là người ký duyệt. Nguyên tắc xuyên suốt bài này: AI dựng, bạn kiểm.
Chọn cổng: Stripe vs Sepay vs Polar
Chọn cổng trước khi gõ prompt, vì mỗi cổng có luồng và payload riêng. Ba lựa chọn phổ biến cho dev Việt:
| Tiêu chí | Stripe | Sepay | Polar |
|---|---|---|---|
| Khách mục tiêu | Quốc tế, thẻ tín dụng | Việt Nam, VND | SaaS toàn cầu |
| Phương thức | Thẻ, ví, Checkout hosted | VietQR/NAPAS, chuyển khoản, thẻ, 44+ ngân hàng | Thẻ qua Merchant of Record |
| Điểm mạnh | Hệ sinh thái lớn, Connect cho marketplace | Nhận tiền nội địa mượt, phí thấp, QR động | Tự lo thuế/VAT toàn cầu, subscription, trial |
| Hợp khi | Bán ra nước ngoài | Bán cho khách VN | Bán phần mềm/subscription xuyên biên giới |
Khuyến nghị gọn: khách Việt Nam thì Sepay (VietQR/NAPAS, khách quét mã chuyển khoản, tiền vào tài khoản ngân hàng của bạn); khách quốc tế trả thẻ thì Stripe; bán SaaS toàn cầu và ngại xử lý thuế thì Polar vì họ đứng vai Merchant of Record tự lo VAT. Nhiều app Việt chạy song song Stripe + Sepay: khách nước ngoài đi Stripe, khách trong nước đi VietQR. Bài này đi sâu vào hai cổng đó, còn Polar thì luồng tương tự Stripe (có adapter Next.js riêng).
Chuẩn bị trước khi bắt đầu
Checklist trước khi mở Claude Code (soát nhanh, thiếu cái nào bổ sung cái đó):
- App Next.js hoặc Node/Express đã chạy được local.
- Tài khoản Stripe ở test mode, hoặc tài khoản Sepay ở sandbox (khoá dạng
SP-TEST-*). - Các khoá bí mật để trong
.envvà không commit - thêm.envvào.gitignoretrước tiên. - Claude Code đã cài, và repo có file
CLAUDE.mdmô tả stack + quy ước (phần sau sẽ dùng tới). - Một endpoint public để cổng gọi webhook - local thì dùng Stripe CLI hoặc một tunnel; production thì dùng HTTPS thật.
Việc xử lý khoá bí mật là chỗ dễ hỏng nhất về bảo mật, nên xem thêm cách quản lý permissions an toàn cho Claude Code để không vô tình để agent đọc hoặc in secret ra log.
Cách "brief" Claude Code cho tác vụ thanh toán
Chất lượng output phụ thuộc gần như hoàn toàn vào cách bạn brief. Với thanh toán, hai thứ quan trọng nhất là context trong CLAUDE.md và một prompt cụ thể.
Thêm vài dòng context này vào CLAUDE.md để Claude Code không đoán mò:
# Payment context
- Stack: Next.js 15 App Router, TypeScript, Prisma + PostgreSQL
- Cổng: Stripe (khách quốc tế) + Sepay/VietQR (khách VN)
- Env: mọi secret nằm trong .env, KHÔNG commit, KHÔNG in ra log
- Quy ước: chỉ dùng Stripe Checkout Sessions, KHÔNG dùng Charges/Card Element legacy
- An toàn: KHÔNG tự chạy lệnh production, KHÔNG tự refund; chỉ chạy test mode/sandbox
Sau đó là prompt. So sánh prompt mơ hồ "tích hợp Stripe cho tôi" với một prompt cụ thể:
Đọc app/ và prisma/schema.prisma. Tạo route POST app/api/checkout/route.ts
tạo một Stripe Checkout Session (mode payment) từ priceId trong body,
trả về session.url. Dùng biến env đã có. Không chỉnh file khác.
Sau đó viết test bằng Stripe CLI trong README, đừng tự chạy lệnh live.
Prompt cụ thể giúp Claude Code khoanh vùng thay đổi, dùng đúng schema DB của bạn, và không "sáng tạo" thêm file. Bạn cũng có thể chỉ nó đọc docs cổng qua fetch/MCP (Stripe docs, developer.sepay.vn) để bám đúng API mới nhất thay vì trí nhớ cũ.
Luồng Stripe với Claude Code (khách quốc tế)
Luồng Stripe hiện đại gói gọn trong bốn bước. Ưu tiên Checkout Session (Stripe-hosted), tránh Charges/Card Element legacy vì chúng đã lỗi thời và tăng gánh nặng PCI.
- Route tạo Checkout Session. Brief Claude Code sinh route nhận
priceId, tạo session và trảsession.urlđể client redirect. - Redirect success/cancel. Truyền
success_urlvàcancel_url; đừng ghi nhận đơn "đã trả" ở success page - chờ webhook. - Webhook
checkout.session.completed. Verify chữ ký bằngconstructEventrồi mới xử lý nghiệp vụ. - Test bằng Stripe CLI ngay tại local, không cần deploy.
// app/api/checkout/route.ts
import { NextResponse } from "next/server";
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const { priceId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/cancel`,
});
return NextResponse.json({ url: session.url });
}
// app/api/webhooks/stripe/route.ts
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const body = await req.text(); // cần raw body để verify
const sig = req.headers.get("stripe-signature")!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body, sig, process.env.STRIPE_WEBHOOK_SECRET!
);
} catch {
return new Response("Invalid signature", { status: 400 });
}
if (event.type === "checkout.session.completed") {
// idempotent: kiểm tra event.id đã xử lý chưa rồi mới ghi đơn
}
return new Response("ok", { status: 200 });
}
Test local với hai lệnh, không tốn đồng nào:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
stripe trigger checkout.session.completed
Chi tiết luồng go-live và danh sách kiểm tra chính thức xem tại tài liệu Stripe (docs.stripe.com, truy cập 08/2026) - nên verify API version live trước khi publish vì Stripe cập nhật thường xuyên.
Luồng Sepay/VietQR với Claude Code (khách VN)
Sepay hợp với khách Việt: bạn sinh mã VietQR/tài khoản ảo, khách quét và chuyển khoản, Sepay bắn webhook báo tiền vào. Luồng bốn bước:
- Tạo order + sinh VietQR (hoặc virtual account) ứng với đơn hàng, kèm nội dung chuyển khoản để đối soát.
- Khách quét QR chuyển khoản qua app ngân hàng.
- Webhook Sepay báo giao dịch với
transferType: "in", kèmtransferAmount,content,referenceCode. - Verify + dedup + trả
{"success": true}trong dưới 5 giây để Sepay không retry.
// app/api/webhooks/sepay/route.ts
import { db } from "@/lib/db";
export async function POST(req: Request) {
const auth = req.headers.get("authorization");
if (auth !== `Apikey ${process.env.SEPAY_API_KEY}`) {
return new Response("Unauthorized", { status: 401 });
}
const data = await req.json();
// data: { id, transferType, transferAmount, content, referenceCode }
if (data.transferType !== "in") {
return Response.json({ success: true }); // bỏ qua giao dịch ra
}
const existed = await db.transaction.findUnique({
where: { sepayId: data.id },
});
if (existed) return Response.json({ success: true }); // dedup theo id
await db.transaction.create({
data: {
sepayId: data.id,
amount: data.transferAmount,
content: data.content,
ref: data.referenceCode,
},
});
// TODO: đối soát content với order rồi cập nhật trạng thái "đã trả"
return Response.json({ success: true });
}
Việc lưu giao dịch và đối soát với đơn hàng nên tách sạch ra tầng dữ liệu - xem cách lưu đơn hàng và giao dịch với database để thiết kế bảng orders/transactions gọn. Sepay có sandbox riêng và rate limit 2 req/s, cứ để Claude Code đọc tài liệu chính thức (developer.sepay.vn, truy cập 08/2026) để bám đúng endpoint và payload.
Webhook và idempotency - phần dễ sai nhất
Đây là chỗ tutorial thủ công hay bỏ qua và cũng là chỗ gây hậu quả nặng nhất. Cổng thanh toán không đảm bảo gửi webhook đúng một lần: mạng chập chờn, timeout, hay retry đều khiến cùng một sự kiện đến nhiều lần. Nếu handler không idempotent, bạn ghi đơn trùng, cộng số dư hai lần, hoặc giao hàng lặp.
Nguyên tắc: dedup theo định danh sự kiện. Với Sepay là id giao dịch; với Stripe là event.id. Lưu id đã xử lý (unique index trong DB) và bỏ qua nếu đã thấy. Với ca phức tạp, dùng composite key (ví dụ orderId + loại sự kiện).
Ràng buộc thời gian và retry cần nhớ:
- Sepay: handler phải trả 2xx trong dưới 5 giây; nếu không, Sepay auto-retry tới 7 lần trong khoảng 5 giờ theo bước Fibonacci. Nghĩa là cùng giao dịch có thể tới 7 lần - dedup là bắt buộc.
- Stripe: retry theo lịch riêng khi không nhận 2xx; vẫn cần dedup theo
event.id.
Mẹo thực chiến: lưu event trước, xử lý nghiệp vụ sau. Ghi bản ghi event (idempotent) rồi mới chạy logic nặng ở bước tách biệt, để nếu logic lỗi thì retry vẫn an toàn. Đây là chỗ nên yêu cầu Claude Code viết test cho ca "webhook đến hai lần" - nó thường quên nếu bạn không nhắc.
Test và bảo mật trước khi go-live
Trước khi bật tiền thật, soát checklist này (đây cũng là mục tutorial thủ công thường thiếu):
Test:
- Stripe: dùng Stripe CLI (
stripe listen/stripe trigger) và thẻ test; không đụng tiền thật. - Sepay: dùng sandbox với khoá
SP-TEST-*; giả lập giao dịch vào và kiểm tra webhook. - Test ca lỗi: chữ ký sai, webhook đến hai lần, số tiền không khớp order.
Bảo mật:
- Không lộ secret key - chỉ dùng ở server, không đưa vào client bundle, không in ra log.
- Verify mọi webhook: Stripe qua chữ ký HMAC (
constructEvent), Sepay qua API Key headerAuthorization: Apikey .... - Bắt buộc HTTPS ở production; cân nhắc IP whitelist cho endpoint webhook.
- Chỉ dùng Checkout Sessions / PaymentIntents / SetupIntents; tránh Sources/Tokens/Charges legacy để giảm phạm vi PCI. Nếu chạm raw PAN, bạn rơi vào diện chứng minh PCI phức tạp - đừng.
Go-live: Stripe có go-live checklist riêng (chuyển sang live key, cấu hình webhook production). Sepay cần duyệt NAPAS QR/thẻ, thường 3-7 ngày - tính vào lịch. Trước khi publish, chạy thêm một lượt bảo mật và security audit bằng Claude Code để soát rò rỉ khoá và lỗ hổng verify.
Làm nhanh gấp bội với skill dựng sẵn (AgentKit)
Nếu không muốn viết tay từng handler, có một cách nhanh hơn: dùng skill ak-payment-integration trong AgentKit Engineer Kit. Skill này đã đóng gói sẵn cả ba cổng SePay + Polar + Stripe - checkout, webhook verify (kèm script sẵn), QR, subscriptions, multi-provider orders - nên Claude Code chỉ việc kích hoạt và dựng trong vài phút thay vì mò docs từng cổng.
Một dòng để tránh nhầm: AgentKit ở đây là bộ kit cho Claude Code tại agentkit.best (giảm 20% qua link) (CLI ak), không phải OpenAI AgentKit. Engineer Kit có giá $99 (trang không nêu phí định kỳ). Nếu muốn xem skill này giải quyết được gì cụ thể, đọc bài Engineer Kit review chi tiết và AgentKit là gì trước khi quyết định - đừng mua chỉ vì một skill nếu bạn chỉ cần đúng một luồng.
Giới hạn và lưu ý khi để AI đụng tiền
Thanh toán gần với YMYL, nên phần này quan trọng ngang phần code. Vài ranh giới cứng khi để Claude Code làm payment:
- Luôn review code liên quan tiền tệ. Đọc kỹ chỗ tính tiền, quy đổi đơn vị, và điều kiện cập nhật trạng thái đơn.
- Đừng để agent tự chạy lệnh production hay refund. Giữ Claude Code trong test mode/sandbox; lệnh live do bạn tự bấm sau khi review.
- Verify số tiền và đơn vị. Stripe tính bằng đơn vị nhỏ nhất (cent); VND không có phần thập phân - đây là chỗ AI hay sai khi quy đổi.
- Test kỹ webhook edge case (đến hai lần, sai chữ ký, số tiền lệch) và giữ log để đối soát khi có tranh chấp.
Tóm lại: AI giúp bạn đi nhanh, nhưng trách nhiệm về tiền vẫn là của bạn. Tốc độ không thay thế được một lượt review tỉnh táo.
Câu hỏi thường gặp (FAQ)
Claude Code có tự tích hợp thanh toán hết cho tôi không?
Nó dựng phần lớn: đọc repo, sinh route checkout, viết webhook handler, viết test. Nhưng bạn vẫn phải review code, tự đăng ký cổng, tự cấu hình khoá production và tự bấm lệnh go-live. Vì đụng tiền, con người là người ký duyệt cuối.
Khách hàng Việt Nam thì nên chọn Stripe hay Sepay?
Với khách Việt trả bằng VND, Sepay hợp hơn nhờ VietQR/NAPAS, chuyển khoản qua 44+ ngân hàng và tiền vào thẳng tài khoản của bạn. Stripe hợp khi bán ra quốc tế và nhận thẻ tín dụng. Nhiều app chạy cả hai song song.
Webhook không nhận được giao dịch thì xử lý sao?
Kiểm tra endpoint có public và HTTPS không, chữ ký/API Key verify có đúng không, và handler có trả 2xx dưới 5 giây không. Sepay tự retry tới 7 lần trong khoảng 5 giờ, nên nếu handler idempotent thì lần retry sau vẫn ghi nhận đúng.
Làm sao test luồng thanh toán mà không mất tiền thật?
Dùng test mode: Stripe có Stripe CLI (stripe listen/stripe trigger) và thẻ test; Sepay có sandbox với khoá SP-TEST-*. Cả hai cho bạn giả lập giao dịch và webhook mà không đụng tiền thật.
Không rành code có làm theo bài này được không?
Bạn cần biết code cơ bản để đọc và review được diff mà Claude Code tạo ra - vì đụng tiền, bạn không nên merge code mình không hiểu. Claude Code giảm khối lượng gõ tay, nhưng khả năng đọc hiểu vẫn cần thiết.
Skill ak-payment-integration khác gì so với tự viết tay?
Tự viết tay thì bạn kiểm soát từng dòng nhưng tốn thời gian mò docs ba cổng. Skill ak-payment-integration đóng gói sẵn checkout, webhook verify, QR và subscriptions cho SePay/Polar/Stripe, giúp dựng nhanh hơn; đổi lại bạn vẫn nên review output vì mỗi app có nghiệp vụ riêng.
Kết luận và bước tiếp theo
Nhắc lại năm bước: chọn cổng (Stripe quốc tế / Sepay cho khách VN) → brief Claude Code kèm CLAUDE.md → tạo checkout → viết webhook idempotent → test và bảo mật rồi mới go-live. Điểm sống còn là webhook idempotent và một lượt review của con người vì đây là tiền thật. Từ đây, bạn có thể đi tiếp sang dựng API backend hoàn chỉnh hoặc siết security audit trước khi phát hành.
Muốn dựng luồng thanh toán nhanh hơn? Skill ak-payment-integration trong Engineer Kit đóng gói sẵn checkout, webhook verify và QR cho Stripe/Sepay/Polar - hợp khi bạn cần dựng nhiều cổng mà không muốn mò docs từng cái.