PaymentIntent 自訂表單
當結帳必須留在你的網域、版面要完全自訂時,使用 PaymentIntent 加上前端的 Payment Element。這是本 repo server.py + public/ 的做法。
官方文件:Accept a payment。官方逐步影片(Python)已嵌在 官方影音。
和 Checkout 差在哪
Checkout:伺服器建立 Session,瀏覽器離開(或嵌入整頁 Checkout)。
PaymentIntent:伺服器只建立「要收多少錢」的 Intent,瀏覽器留在你的 HTML,由 Stripe.js 畫卡號欄位並呼叫 confirmPayment。
你要自己處理:載入 Stripe.js、錯誤訊息、3DS 導回、以及同樣不可少的 webhook。
後端:建立 PaymentIntent
金額仍在伺服器算。不要用前端傳來的 amount。
import json
import os
import stripe
from flask import Flask, jsonify, render_template, request
app = Flask(__name__, static_folder="public", static_url_path="", template_folder="public")
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
def calculate_order_amount(items):
# 以伺服器價格為準;這裡示範固定 NT$140(若改 USD 則是 1400 分)
return 1400
@app.get("/checkout")
def checkout():
return render_template("checkout.html")
@app.post("/create-payment-intent")
def create_payment():
data = json.loads(request.data)
intent = stripe.PaymentIntent.create(
amount=calculate_order_amount(data.get("items", [])),
currency="usd",
automatic_payment_methods={"enabled": True},
metadata={"sku": "xl-tshirt"},
)
return jsonify({"clientSecret": intent.client_secret})
client_secret 可以給前端,它只能確認這一筆 Intent,不能列出金鑰或改金額。Secret API key 仍然只能留在伺服器。
automatic_payment_methods 讓 Dashboard 勾選的付款方式自動出現在表單,不必改程式。
前端:掛上 Payment Element
checkout.html 需要 Stripe.js 與一個空的掛載點:
<script src="https://js.stripe.com/v3/"></script>
<form id="payment-form">
<div id="payment-element"></div>
<button id="submit">Pay now</button>
<div id="payment-message"></div>
</form>
checkout.js 的核心步驟:
const stripe = Stripe("pk_test_你的公開金鑰");
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
});
const { clientSecret } = await response.json();
const elements = stripe.elements({ clientSecret });
elements.create("payment").mount("#payment-element");
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "http://localhost:4242/checkout",
},
});
confirmPayment 會把卡號送到 Stripe。若需要 3D Secure,Stripe 會導向銀行再回到 return_url。頁面可用 query 裡的 payment_intent_client_secret 呼叫 retrievePaymentIntent 顯示結果。
完整檔案在 repo 的 public/checkout.html、public/checkout.js、public/checkout.css。逐步對照見 本 repo 範例。
務必接 webhook
Intent 變成 succeeded 時,要聽 payment_intent.succeeded。不要只靠 return_url。見 Webhook 履約。
什麼時候不要用這條路
賣單一商品、沒有複雜結帳 UI,用 Checkout 比較省事,稅與優惠券也比較完整。PaymentIntent 適合已經有自己的購物車 UI、必須高度客製的產品。