Stripe是什麼?
Stripe 是一個提供金流付費服務的的平台。
它提供各種支付方式、一次性和訂閱的付款服務
讓你可以輕鬆管理線上支付業務。
幾乎所有知名的網站
如 ChatGPT, Google, Netflix
都選擇使用Stripe進行訂閱付款。
Stripe API 付款流程

- 在遊戲中點擊購買按鈕
- 呼叫Stripe API → 取得付款連結
- 自動打開瀏覽器 → 用戶進行付款
- 遊戲在後台循環偵測付款狀態
- 處理付款完成後的邏輯
串接 Stripe API 的準備
注意: 註冊 Stripe 帳號需要有一間公司
這篇文章預設你已經註冊好Stripe帳號了。
1. 打開測試模式

登入Stripe網站後
右上角可以打開測試模式
在開發測試階段打開測試模式
就不會收取真錢。
在測試模式下
可以輸入測試信用卡 4242-4242-4242 來付款
2. 取得Stripe API密鑰
點擊開發人員→API密鑰→顯示密鑰。
API Key 會在呼叫Stripe API時用到
可以先保存起來。
3. 新增產品目錄
到產品目錄的頁面,點擊添加產品。

我們要新增兩個產品,第一個是一次性購買的
第二個是訂閱模式的:
4. 取得商品的價錢ID
把創建的產品點開 → 找到價格(再點開)
右上角有一個 price_xxx 的價錢ID
這個過後帶入參數會用到,先複製保存下來。
訂閱的產品也是一樣的操作。
5. 總結
操作完上面的步驟之後,你會得到- Stripe API Key
- 一次性商品的 Price ID
- 訂閱模式的 Price ID
需要的 Stripe API
Stripe API的說明文件: https://docs.stripe.com/api
很多,但我們一共要知道的只有4個API:
- Create Session API – 創建付款連結的API
- Check Session API – 取得付款狀態的API
- Check Subscribe Status API – 檢查訂閱狀態的API
- Unsubscribe API – 取消訂閱的API
Endpoint: https://api.stripe.com/v1/checkout/sessions
類型: POST
| 參數 | 解釋 |
|---|---|
| payment_method_types[] | card |
| mode | payment // 一次性 subscription // 訂閱制 |
| success_url | 成功後跳轉的URL |
| cancel_url | 失敗/取消後跳轉的URL |
| customer_email | 用戶的Email |
| line_items[0][price] | 價格的 Price ID // price_xxx |
| line_items[0][quantity] | 購買數量 // 1 |
1{2 "id": "cs_test_a11YYufWQzNY63zpQ6QSNRQhkUpVph4WRmzW0zWJO2znZKdVujZ0N0S22u",3 "object": "checkout.session",4 "after_expiration": null,5 "allow_promotion_codes": null,6 "amount_subtotal": 2198,7 "amount_total": 2198,8 "automatic_tax": {9 "enabled": false,10 "liability": null,11 "status": null12 },13 "billing_address_collection": null,14 "cancel_url": null,15 "client_reference_id": null,16 "consent": null,17 "consent_collection": null,18 "created": 1679600215,19 "currency": "usd",20 "custom_fields": [],21 "custom_text": {22 "shipping_address": null,23 "submit": null24 },25 "customer": null,26 "customer_creation": "if_required",27 "customer_details": null,28 "customer_email": null,29 "expires_at": 1679686615,30 "invoice": null,31 "invoice_creation": {32 "enabled": false,33 "invoice_data": {34 "account_tax_ids": null,35 "custom_fields": null,36 "description": null,37 "footer": null,38 "issuer": null,39 "metadata": {},40 "rendering_options": null41 }42 },43 "livemode": false,44 "locale": null,45 "metadata": {},46 "mode": "payment",47 "payment_intent": null,48 "payment_link": null,49 "payment_method_collection": "always",50 "payment_method_options": {},51 "payment_method_types": [52 "card"53 ],54 "payment_status": "unpaid",55 "phone_number_collection": {56 "enabled": false57 },58 "recovered_from": null,59 "setup_intent": null,60 "shipping_address_collection": null,61 "shipping_cost": null,62 "shipping_details": null,63 "shipping_options": [],64 "status": "open",65 "submit_type": null,66 "subscription": null,67 "success_url": "https://example.com/success",68 "total_details": {69 "amount_discount": 0,70 "amount_shipping": 0,71 "amount_tax": 072 },73 "url": "https://checkout.stripe.com/c/pay/cs_test_a11YYufWQzNY63zpQ6QSNRQhkUpVph4WRmzW0zWJO2znZKdVujZ0N0S22u#fidkdWxOYHwnPyd1blpxYHZxWjA0SDdPUW5JbmFMck1wMmx9N2BLZjFEfGRUNWhqTmJ%2FM2F8bUA2SDRySkFdUV81T1BSV0YxcWJcTUJcYW5rSzN3dzBLPUE0TzRKTTxzNFBjPWZEX1NKSkxpNTVjRjN8VHE0YicpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl"74}我們需要用到的是最後一行的付款URL
呼叫API的時候需要在 Header 帶入Bearer Token – API Key
實作Unity C# 代碼
1. 先把Interface需要的功能列出來
1public interface IPaymentServices2{3 public void Initialize(string apiKey, Action<object> callback);4 public void Pay(object sessionModel);5 public void Subscribe(object sessionModel);6 public void GetPaymentStatus(string sessionId, Action<object> callback);7 public void GetSubscribeStatus(string subscribeId, Action<object> callback);8 public void Unsubscribe(string subscribeId);9}2. 實作這個Interface
StripeServices.cs
1 public class StripeServices : IPaymentServices{2 3 //定義 Stripe API 的 Endpoint4 private string SessionRoute = "https://api.stripe.com/v1/checkout/sessions";5 6 private string SubscribeRoute = "https://api.stripe.com/v1/subscriptions";7
8 private string ApiKey = "sk_stripe_secret_key";9 private Action<object> sessionIdCallback;10
11 // 一開始使用的時候要把API Key帶進來12 public void Initialize(string key, Action<object> callback)13 {14 ApiKey = key;15 sessionIdCallback = callback;16 }17
18 // 一次性付款的時候呼叫19 public void Pay(object sessionModel)20 {21 var session = sessionModel as StripeSessionRequestModel;22 if (session == null)23 {24 Debug.Log("Session Info Is Null");25 return;26 }27
28 session.mode = "payment";29 30CoroutineManager.StartStaticCoroutine(CreateCheckoutSession(session));31 }32 33
34 // 訂閱模式35 public void Subscribe(object sessionModel)36 {37 var session = sessionModel as StripeSessionRequestModel;38 if (session == null)39 {40 Debug.Log("Session Info Is Null");41 return;42 }43
44 session.mode = "subscription";45 session.successUrl += "?type=vip&subscribeId=null";46 CoroutineManager.StartStaticCoroutine(CreateCheckoutSession(session));47 }48
49 // 取得付款狀況50 public void GetPaymentStatus(string sessionId, Action<object> callback)51 {52 CoroutineManager.StartStaticCoroutine(GetSessionStatus(sessionId, callback));53 }54
55 // 取得訂閱狀況56 public void GetSubscribeStatus(string subscribeId, Action<object> callback)57 {58 CoroutineManager.StartStaticCoroutine(GetSubscribeStatusCoroutine(subscribeId, callback));59 }60
61 // 取消訂閱62 public void Unsubscribe(string subscribeId)63 {64 CoroutineManager.StartStaticCoroutine(CancelSubscribeCoroutine(subscribeId,null));65 }66
67 // 使用Unity的 Webrequest 呼叫Stripe 的API68 private IEnumerator CreateCheckoutSession(StripeSessionRequestModel sessionModel)69 {70 var form = new WWWForm();71 form.AddField("mode", sessionModel.mode);72 form.AddField("customer_email", sessionModel.customerEmail);73 form.AddField("line_items[0][price]", sessionModel.priceId);74 form.AddField("line_items[0][quantity]", sessionModel.quantity);75 form.AddField("success_url", sessionModel.successUrl);76 form.AddField("cancel_url", sessionModel.cancelUrl);77 form.AddField("payment_method_types[0]", "card");78
79 using var www = UnityWebRequest.Post(SessionRoute, form);80 www.SetRequestHeader("Authorization", "Bearer " + ApiKey);81 www.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");82 yield return www.SendWebRequest();83
84 if (www.result != UnityWebRequest.Result.Success)85 {86 Debug.LogError("Stripe Call Error: " + www.error);87 }88 else89 {90 Debug.Log("Stripe Response: " + www.downloadHandler.text);91 var response = JsonConvert.DeserializeObject<StripeSessionResponseModel>(www.downloadHandler.text);92 sessionIdCallback?.Invoke(response.id);93 Application.OpenURL(response.url);94 }95 }96 97 private IEnumerator GetSessionStatus(string sessionId, Action<object> callback)98 {99 using var www = UnityWebRequest.Get(SessionRoute + $"/{sessionId}");100 www.SetRequestHeader("Authorization", "Bearer " + ApiKey);101 yield return www.SendWebRequest();102 if (www.result != UnityWebRequest.Result.Success)103 {104 Debug.LogError("Stripe Call Error: " + www.error);105 }106 else107 {108 Debug.Log("Stripe Response: " + www.downloadHandler.text);109 var response = JsonConvert.DeserializeObject<StripeSessionStatusModel>(www.downloadHandler.text);110 callback?.Invoke(response);111 }112 }113 114 private IEnumerator GetSubscribeStatusCoroutine(string subscribeId, Action<object> callback)115 {116 using var www = UnityWebRequest.Get(SessionRoute + $"/{subscribeId}");117 www.SetRequestHeader("Authorization", "Bearer " + ApiKey);118 yield return www.SendWebRequest();119 if (www.result != UnityWebRequest.Result.Success)120 {121 Debug.LogError("Stripe Call Error: " + www.error);122 }123 else124 {125 Debug.Log("Stripe Response: " + www.downloadHandler.text);126 var response = JsonConvert.DeserializeObject<StripeSubscribeStatusModel>(www.downloadHandler.text);127 callback?.Invoke(response);128 }129 }130 131 private IEnumerator CancelSubscribeCoroutine(string subscribeId, Action<object> callback)132 {133 using var www = UnityWebRequest.Delete(SubscribeRoute + $"/{subscribeId}");134 www.SetRequestHeader("Authorization", "Bearer " + ApiKey);135 yield return www.SendWebRequest();136 if (www.result != UnityWebRequest.Result.Success)137 {138 Debug.LogError("Stripe Call Error: " + www.error);139 }140 else141 {142 Debug.Log("Stripe Response: " + www.downloadHandler.text);143 var response = JsonConvert.DeserializeObject<StripeSubscribeStatusModel>(www.downloadHandler.text);144 callback?.Invoke(response);145 }146 }147}Unity UI Scene
製作一個簡單的UI介面:
- 付款按鈕
- 訂閱按鈕
- 取消訂閱按鈕
- 客戶的Member狀態
- 金幣數量的顯示
調用代碼:
StripeView.cs
1public class StripeLabsView : MonoBehaviour2{3 public string StripeSecretApiKey;4
5 public string CustomerEmail;6
7 [Header("One Time Pay Info")] 8 public string PayPriceId;9 public string PayPriceQuantity;10 public string PaySuccessUrl;11 public string PayCancelUrl;12
13 [Header("Subscribe Info")] 14 public string SubscribePriceId;15 public string SubscribePriceQuantity;16 public string SubscribeSuccessUrl;17 public string SubscribeCancelUrl;18
19 public Button PayBtn;20 public Button SubscribeBtn;21 public Button UnsubscribeBtn;22
23 public Text MemberTypeText;24 public Text CoinText;25
26 public GameObject LoadingObj;27 public Button CancelLoadingBtn;28
29 public string GetCoinRoute = "https://bll2sj.buildship.run/GetCoin";30 public string GetMemberRoute = "https://bll2sj.buildship.run/GetType";31
32 private IPaymentServices PaymentServices = new StripeServices();33 private string currentSessionId;34 private StripeSessionStatusModel currentSessionStatus;35
36 private void Start()37 {38 PayBtn.onClick.AddListener(PayBtnOnClick);39 SubscribeBtn.onClick.AddListener(SubscribeBtnOnClick);40 PaymentServices.Initialize(StripeSecretApiKey, sessionIdCallback);41 CancelLoadingBtn.onClick.AddListener(() => LoadingObj.SetActive(false));42 CoroutineManager.Instance.StartCoroutine(GetCoin());43 CoroutineManager.Instance.StartCoroutine(GetMemberType());44 }45
46 private void sessionIdCallback(object obj)47 {48 currentSessionId = obj as string;49 }50
51 private void PayBtnOnClick()52 {53 var sessionInfo = new StripeSessionRequestModel()54 {55 mode = "payment",56 customerEmail = CustomerEmail,57 priceId = PayPriceId,58 quantity = PayPriceQuantity,59 successUrl = PaySuccessUrl,60 cancelUrl = PayCancelUrl61 };62 PaymentServices.Pay(sessionInfo);63 LoadingObj.SetActive(true);64 CoroutineManager.Instance.StartCoroutine(CheckSessionStatusLoop());65 }66
67 private void SubscribeBtnOnClick()68 {69 var sessionInfo = new StripeSessionRequestModel()70 {71 mode = "subscription",72 customerEmail = CustomerEmail,73 priceId = SubscribePriceId,74 quantity = SubscribePriceQuantity,75 successUrl = SubscribeSuccessUrl,76 cancelUrl = SubscribeCancelUrl77 };78 PaymentServices.Subscribe(sessionInfo);79 LoadingObj.SetActive(true);80 CoroutineManager.Instance.StartCoroutine(CheckSessionStatusLoop());81 }82
83 private IEnumerator GetCoin()84 {85 using var www = UnityWebRequest.Get(GetCoinRoute);86 yield return www.SendWebRequest();87 if (www.result != UnityWebRequest.Result.Success)88 {89 Debug.LogError("Get Coin Call Error: " + www.error);90 }91 else92 {93 CoinText.text = www.downloadHandler.text;94 }95 }96
97 private IEnumerator GetMemberType()98 {99 using var www = UnityWebRequest.Get(GetMemberRoute);100 yield return www.SendWebRequest();101 if (www.result != UnityWebRequest.Result.Success)102 {103 Debug.LogError("Get Member Call Error: " + www.error);104 }105 else106 {107 MemberTypeText.text = www.downloadHandler.text;108 }109 }110
111 private void SessionStatusCallBack(object obj)112 {113 currentSessionStatus = obj as StripeSessionStatusModel;114 }115
116 private IEnumerator CheckSessionStatusLoop()117 {118 currentSessionStatus = new StripeSessionStatusModel();119 currentSessionStatus.payment_status = "waiting";120 yield return new WaitForSeconds(5f);121
122 while (currentSessionStatus.payment_status != "paid")123 {124 Debug.Log(currentSessionStatus.payment_status);125 PaymentServices.GetPaymentStatus(currentSessionId, SessionStatusCallBack);126 yield return new WaitForSeconds(3f);127 }128
129 LoadingObj.SetActive(false);130 CoroutineManager.Instance.StartCoroutine(GetCoin());131 CoroutineManager.Instance.StartCoroutine(GetMemberType());132 }133}3 在Inspector把需要的參數帶入:

BuildShip 後端架設
後端的實作邏輯我是用 Buildship
快速架設一個可以回傳資料庫的Json數值
主要用了幾個簡單的API
可以取得和設定金幣,Member Type:
它背後的資料庫表單長這樣:

Demo影片
一些注意事項:
- 上線時要把Stripe API Key換成正式模式
- 付款後的邏輯你可以寫在後端,用付款跳轉後的連結去處理也可以寫在Unity裡面,判斷付款成功之後處理遊戲邏輯(但這樣要考慮好會不會有安全風險)
- 不想要從遊戲跳轉到網頁的話,可以在遊戲裡面是做一個嵌入式的瀏覽器,在遊戲內完成付款。






