サブスクリプションビジネスに最適なStripe設定:私たちが運用する4つのモデル
過去数年間に私は10回以上Stripe統合を設定してきましたが、ここで学んだことをお話しします。初心者向けチュートリアルは簡単な部分です。難しいのは、同じ組織内で4つの異なる料金モデルを実行し、30以上の国の通貨を丸め誤差なく処理し、ウェブフックハンドラーが土曜日の午前3時にサイレント失敗しないようにすることです。
これは「5分でチェックアウトセッションを作成する」というような別の記事ではありません。私たちが構築・運用している4つの本番環境の料金モデルを段階的に説明します。地域別料金設定を伴うティアード化されたサブスクリプション、Stripe Connectを通じたマーケットプレイスコミッション、特定のエンティティに関連付けられた定期寄付、および1回限りのサービス支払いです。各モデルには独自の落とし穴があり、私たちを痛いバグから救った具体的なコードパターンと設定の決定を共有します。
目次
- 1つのStripe設定がすべてに対応するわけではない理由
- モデル1: 地域別料金設定を伴うティアード化されたサブスクリプション
- モデル2: Stripe Connectを使用したマーケットプレイスコミッション
- モデル3: エンティティに関連付けられた定期寄付
- モデル4: 1回限りのサービス支払い
- 実際に機能するウェブフックアーキテクチャ
- 失敗した支払い再試行ロジックとダニング
- 私たちにお金がかかったゼロ小数通貨バグ
- 4つのモデルの比較
- FAQ

1つのStripe設定がすべてに対応するわけではない理由
Stripeのドキュメントは単一モデルのビジネスに対して優れています。サブスクリプションまたは1回限りの支払いを選択して、ガイドに従い、本番環境にデプロイします。しかし、ほとんどの実在するビジネスは長期間そのままシンプルなままではありません。
私たちは複数の製品に対応しています。ティアード化されたサブスクリプションを持つSaaSプラットフォーム、プロバイダーからコミッションを取得するマーケットプレイス、定期的なスポンサーシップを伴う慈善活動、および1回限りの支払いを伴うコンサルティング予約システムです。これらはすべて同じStripeアカウント下にありますが、製品、料金、ウェブフック、および顧客管理に対して根本的に異なる設定が必要です。
私が見ているチームが犯す最大の誤りは、すべての請求を1つのモデルに強制しようとすることです。サブスクリプション優先のアーキテクチャは、1回限りの支払いが必要な場合に壊れます。チェックアウトセッション専用のアプローチは、按分を伴う定期請求が必要な場合に崩壊します。Stripe設定を請求パターンのポートフォリオとして考える必要があります。
Next.jsまたはAstroフロントエンドを使用したヘッドレスアーキテクチャで同様のものを構築している場合、ここのパターンはあなたに何週間ものデバッグを節約するでしょう。
モデル1: 地域別料金設定を伴うティアード化されたサブスクリプション
これは私たちが実行する最も複雑なモデルであり、最も痛い教訓を教えてくれたものです。セットアップ: 4つのティア(Free、Basic、Pro、Premium)と30以上の国にわたって異なる料金。
Stripeの製品構造
Stripeでは、各ティアは別の製品です。各製品には複数の料金があります。1つの通貨/地域の組み合わせが1つです。これが重要です。単一の料金を使用して自分自身で通貨変換を行おうとしないでください。Stripeの多通貨料金設定はこのために特別に設計されています。
// 地域別料金設定
const REGIONAL_PRICING = {
pro: {
USD: { monthly: 2900, yearly: 29000 }, // $29/月、$290/年
EUR: { monthly: 2700, yearly: 27000 }, // €27/月、€270/年
GBP: { monthly: 2300, yearly: 23000 }, // £23/月、£230/年
JPY: { monthly: 4200, yearly: 42000 }, // ¥4,200/月 -- ¥42.00ではありません!
KRW: { monthly: 38000, yearly: 380000 }, // ₩38,000/月
INR: { monthly: 190000, yearly: 1900000 }, // ₹1,900/月
BRL: { monthly: 14900, yearly: 149000 }, // R$149/月
},
// ... basicおよびpremiumについて繰り返す
};
それらのJPYとKRWの値に気づきましたか?詳細は後で説明しますが、簡潔に言えば、これらはゼロ小数通貨です。JPYに4200を渡すと、Stripeはそれを¥4,200として解釈します。¥42.00ではなく。USDのように100で乗算すると、誰かに¥420,000($2,800)の請求をしてしまい、¥4,200($28)ではありません。私がどうしてそれを知っているかはお尋ねください。
地域別トライアルロジック
すべての地域が無料トライアルを取得するわけではありません。私たちはこれを特定の東南アジア市場で学んだ経験があります。そこではトライアル濫用が他の地域よりもはるかに高かったです。私たちの設定は次のようなものです:
const TRIAL_CONFIG = {
default_trial_days: 14,
excluded_regions: ['VN', 'PH', 'ID', 'TH', 'MM', 'KH', 'LA'],
reduced_trial_regions: {
IN: 7,
BR: 7,
},
};
function getTrialDays(countryCode) {
if (TRIAL_CONFIG.excluded_regions.includes(countryCode)) {
return 0;
}
return TRIAL_CONFIG.reduced_trial_regions[countryCode]
?? TRIAL_CONFIG.default_trial_days;
}
これはサブスクリプション作成時に渡されます:
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: regionalPriceId }],
trial_period_days: getTrialDays(customer.address.country),
payment_behavior: 'default_incomplete',
payment_settings: {
save_default_payment_method: 'on_subscription',
},
expand: ['latest_invoice.payment_intent'],
});
按分動作
誰かが月の途中でBasicからProにアップグレードする場合、次のことを決定する必要があります: 差額をすぐに支払うのか、または次の請求サイクルで支払うのか?私たちは即時支払いでcreate_prorationsを使用します:
const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
items: [{
id: existingItemId,
price: newPriceId,
}],
proration_behavior: 'create_prorations',
payment_behavior: 'pending_if_incomplete',
});
ダウングレードの場合、変更は請求期間の終了時にスケジュールされます。誰も請求書のサプライズクレジット計算を望んでいません。
顧客ポータル
Stripeの顧客ポータルは過小評価されています。独自のサブスクリプション管理UIを構築する代わりに、ポータルを設定して、そこにユーザーをリダイレクトします:
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: `${process.env.APP_URL}/settings/billing`,
});
ダッシュボードで設定して、プランの変更、キャンセル(キャンセル理由調査を伴う--データは素晴らしい)、および支払い方法の更新を許可します。これだけで、おそらく40時間のフロントエンド開発を節約しました。
モデル2: Stripe Connectを使用したマーケットプレイスコミッション
私たちのマーケットプレイスモデルはStripe Connectを使用して、顧客とサービスプロバイダー間の支払いを促進します。プラットフォームは各トランザクションでコミッションを取得します。これはほとんどのチュートリアルが無視しているStripe Connect設定です。
プロバイダーオンボード
マーケットプレイスの各プロバイダーには、Stripe Expressアカウントが必要です。オンボーディングフローはアカウントを作成し、Stripeのホストされたオンボーディングにリダイレクトします:
const account = await stripe.accounts.create({
type: 'express',
country: provider.country,
email: provider.email,
capabilities: {
card_payments: { requested: true },
transfers: { requested: true },
},
business_type: 'individual',
metadata: {
provider_id: provider.id,
platform: 'fme',
},
});
const accountLink = await stripe.accountLinks.create({
account: account.id,
refresh_url: `${process.env.APP_URL}/provider/onboarding/refresh`,
return_url: `${process.env.APP_URL}/provider/onboarding/complete`,
type: 'account_onboarding',
});
重要な詳細: refresh_urlはリンクが期限切れになった場合にStripeがユーザーを送る場所です。これは予想よりも頻繁に発生します。誰かが携帯電話でオンボーディングを開始し、気が散り、後で戻ってきた場合。これを常に適切に処理して、新しいリンクを生成します。
コミッション構造
顧客がサービスを予約するとき、application_fee_amountを含むPaymentIntentを作成します:
const paymentIntent = await stripe.paymentIntents.create({
amount: bookingAmountInCents,
currency: 'usd',
application_fee_amount: Math.round(bookingAmountInCents * 0.15), // 15%プラットフォーム手数料
transfer_data: {
destination: providerStripeAccountId,
},
metadata: {
booking_id: booking.id,
provider_id: provider.id,
customer_id: customer.id,
},
});
15%のコミッションはプラットフォームに行きます。残りの85%(Stripeの処理手数料を差し引いた)はプロバイダーのExpressアカウントに行きます。
支払いスケジューリング
デフォルトでは、StripeはローリングベースでExpressアカウントに支払います。私たちはこれを週次支払いに上書きします。これにより、払い戻しと異議のためのバッファが提供されます:
await stripe.accounts.update(providerStripeAccountId, {
settings: {
payouts: {
schedule: {
interval: 'weekly',
weekly_anchor: 'friday',
},
},
},
});
金曜日の支払いはプロバイダーが月曜日までに銀行口座でお金を見ることを意味します。それは小さなことですが、プロバイダーの満足度と保持にとって非常に重要です。
Connect固有のウェブフック
Stripe Connectを使用すると、プラットフォームと接続されたアカウントの両方のウェブフックを受け取ります。Connect イベント用に別のウェブフックエンドポイントが必要です:
// 通常のウェブフックエンドポイント
app.post('/webhooks/stripe', handlePlatformWebhooks);
// Connectウェブフックエンドポイント
app.post('/webhooks/stripe-connect', handleConnectWebhooks);
Connect ウェブフックハンドラーは異なる方法でイベントを検証し、accountフィールドを確認する必要があります:
async function handleConnectWebhooks(req, res) {
const event = stripe.webhooks.constructEvent(
req.body,
req.headers['stripe-signature'],
process.env.STRIPE_CONNECT_WEBHOOK_SECRET // 異なるシークレット!
);
const connectedAccountId = event.account;
// 今、接続されたアカウントのコンテキストでイベントを処理します
}

モデル3: エンティティに関連付けられた定期寄付
これは私たちが構築している動物慈善活動のためのものです。「特定の動物をスポンサー」を考えてください。毎月の定期寄付を伴う。寄付者は動物を選択し、毎月の金額を設定し、写真更新を取得します。
エンティティにリンクされたサブスクリプション
ここでのコツはStripeサブスクリプションをデータベース内の特定のエンティティ(動物)にリンクすることです。私たちはこれを完全にメタデータを通じて行います:
const subscription = await stripe.subscriptions.create({
customer: donorCustomerId,
items: [{
price_data: {
currency: 'usd',
product: sponsorshipProductId,
unit_amount: donorChosenAmount, // 寄付者が金額を選択
recurring: {
interval: 'month',
},
},
}],
metadata: {
entity_id: animal.id,
entity_type: 'animal',
entity_name: animal.name,
sponsor_email: donor.email,
},
});
事前に作成された料金の代わりにprice_dataを使用すると、寄付者は自分の毎月の金額を選択できます。これは数百の料金オブジェクトを作成するよりもクリーンです。
月次更新メール
invoice.paidがスポンサーシップサブスクリプションのために発火するとき、月次更新フローをトリガーします:
async function handleSponsorshipInvoicePaid(invoice) {
const subscription = await stripe.subscriptions.retrieve(invoice.subscription);
const entityId = subscription.metadata.entity_id;
// 最新の写真を伴う月次更新メールをキューに入れる
await emailQueue.add('sponsorship-update', {
donorEmail: subscription.metadata.sponsor_email,
entityId,
invoiceAmount: invoice.amount_paid,
invoicePdf: invoice.invoice_pdf,
});
}
メールには請求書PDF(Stripeはこれらを自動的に生成します)、スポンサーされた動物の最新の写真、およびケア更新が含まれます。定期寄付のチャーンを劇的に減らす小さなタッチです。
寄付キャンセル処理
誰かがスポンサーシップをキャンセルするとき、SaaS キャンセルと異なる方法で処理する必要があります。「ダウングレード」がありません。キャンセルするか何もしないか。しかし、後で再度購読しやすくしたいです:
async function handleSponsorshipCancellation(subscription) {
const entityId = subscription.metadata.entity_id;
// スポンサーシップを削除ではなく非アクティブとしてマーク
await db.sponsorships.update({
where: { stripeSubscriptionId: subscription.id },
data: {
status: 'inactive',
cancelledAt: new Date(),
},
});
// 「逃げ出すのが恋しい」メールを簡単な再購読リンク付きで送信
await sendCancellationEmail(subscription.metadata.sponsor_email, entityId);
}
モデル4: 1回限りのサービス支払い
最もシンプルなモデルですが、それでも重要な詳細があります。このパターンはコンサルティング予約の場合で、誰かが1回支払い、サービスを取得します。定期請求なし。
予約データを伴うチェックアウトセッション
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{
price: consultationPriceId,
quantity: 1,
}],
customer_email: customer.email,
metadata: {
booking_id: booking.id,
service_type: 'consultation',
appointment_date: booking.date.toISOString(),
practitioner_id: booking.practitionerId,
},
success_url: `${process.env.APP_URL}/booking/confirmed?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.APP_URL}/booking/${booking.id}`,
expires_after: 1800, // 30分
payment_intent_data: {
metadata: {
booking_id: booking.id,
},
},
});
注意する2つのこと。まず: expires_afterは放棄されたチェックアウトセッションが長期間持続するのを防ぎます。予約スロットは永遠に保持されるべきではありません。2番目: チェックアウトセッションメタデータはPaymentIntentメタデータとは別であるため、booking_idをpayment_intent_data.metadataに複製します。payment_intent.succeededウェブフックを受け取るとき、その予約IDをそこに直接取得したいのです。
支払い + 予約確認
checkout.session.completedで、予約を確認し、すべてを1ショットで送信します:
async function handleCheckoutComplete(session) {
const bookingId = session.metadata.booking_id;
// 予約を確認
const booking = await db.bookings.update({
where: { id: bookingId },
data: {
status: 'confirmed',
paymentSessionId: session.id,
paidAt: new Date(),
},
});
// 顧客に確認を送信
await sendBookingConfirmation(session.customer_email, booking);
// 実践者に通知
await notifyPractitioner(booking.practitionerId, booking);
}
実際に機能するウェブフックアーキテクチャ
4つのモデルすべてにおいて、ウェブフックはバックボーンです。これは、多すぎるデバッグセッションの後に落ち着いたアーキテクチャです:
const WEBHOOK_HANDLERS = {
'checkout.session.completed': handleCheckoutComplete,
'invoice.paid': handleInvoicePaid,
'invoice.payment_failed': handlePaymentFailed,
'customer.subscription.created': handleSubscriptionCreated,
'customer.subscription.updated': handleSubscriptionUpdated,
'customer.subscription.deleted': handleSubscriptionDeleted,
'account.updated': handleConnectAccountUpdated,
'payment_intent.succeeded': handlePaymentSucceeded,
};
async function webhookHandler(req, res) {
let event;
try {
event = stripe.webhooks.constructEvent(
req.rawBody, // 解析されたJSONではなく、生のボディが必要です
req.headers['stripe-signature'],
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
console.error('Webhook署名検証失敗:', err.message);
return res.status(400).send();
}
// べき等性: このイベントを既に処理したかどうかを確認
const processed = await db.webhookEvents.findUnique({
where: { stripeEventId: event.id },
});
if (processed) {
return res.status(200).json({ received: true, duplicate: true });
}
const handler = WEBHOOK_HANDLERS[event.type];
if (handler) {
try {
await handler(event.data.object, event);
await db.webhookEvents.create({
data: { stripeEventId: event.id, type: event.type, processedAt: new Date() },
});
} catch (err) {
console.error(`${event.type}の処理エラー:`, err);
return res.status(500).send(); // Stripeは再試行します
}
}
res.status(200).json({ received: true });
}
べき等性チェックは重要です。Stripeは失敗したウェブフックを再試行し、同じイベントを2回処理したくありません。特に予約の作成や支払い実行のようなことの場合。
失敗した支払い再試行ロジックとダニング
Stripeには組み込みのスマート再試行がありますが、独自のダニングロジックを上に層化する必要があります:
async function handlePaymentFailed(invoice) {
const attemptCount = invoice.attempt_count;
const subscription = await stripe.subscriptions.retrieve(invoice.subscription);
if (attemptCount === 1) {
// 最初の失敗: 優しい促し
await sendEmail(invoice.customer_email, 'payment-failed-soft', {
updatePaymentUrl: await createPortalLink(invoice.customer),
});
} else if (attemptCount === 2) {
// 2番目の失敗: より緊急
await sendEmail(invoice.customer_email, 'payment-failed-urgent', {
updatePaymentUrl: await createPortalLink(invoice.customer),
daysUntilCancellation: 7,
});
} else if (attemptCount >= 3) {
// 最終警告
await sendEmail(invoice.customer_email, 'payment-failed-final', {
updatePaymentUrl: await createPortalLink(invoice.customer),
});
}
}
Stripe再試行スケジュールをダッシュボード→設定→サブスクリプションおよびメール→失敗した支払いを管理で設定します。キャンセル前の14日間で3回の再試行を使用します。
私たちにお金がかかったゼロ小数通貨バグ
これはそれ自体のセクションに値します。これはすべてを最終的に咬むバグだからです。Stripeはほとんどの通貨に対してセント(最小通貨単位)を使用します。$29.00は2900になります。しかし、いくつかの通貨には小数位がありません。
重要なゼロ小数通貨は次のとおりです:
| 通貨 | コード | 例: "$29相当" | Stripeに渡す値 |
|---|---|---|---|
| 日本円 | JPY | ¥4,200 | 4200 (ではなく420000) |
| 韓国ウォン | KRW | ₩38,000 | 38000 (ではなく3800000) |
| ベトナムドン | VND | ₫700,000 | 700000 |
| チリペソ | CLP | $25,000 | 25000 |
| パラグアイグアラニー | PYG | ₲200,000 | 200000 |
ここが私たちがいたるところで使用するユーティリティ関数です:
const ZERO_DECIMAL_CURRENCIES = [
'BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW',
'MGA', 'PYG', 'RWF', 'UGX', 'VND', 'VUV', 'XAF',
'XOF', 'XPF',
];
function toStripeAmount(amount, currency) {
const curr = currency.toUpperCase();
if (ZERO_DECIMAL_CURRENCIES.includes(curr)) {
return Math.round(amount); // 既に最小単位
}
return Math.round(amount * 100);
}
function fromStripeAmount(stripeAmount, currency) {
const curr = currency.toUpperCase();
if (ZERO_DECIMAL_CURRENCIES.includes(curr)) {
return stripeAmount;
}
return stripeAmount / 100;
}
これをどこでも使用します。チェックアウト作成で、ウェブフックハンドラーで、ダッシュボード表示で。どこでも。忘れる1回が誰かを予想の100倍請求する回です。
4つのモデルの比較
| 側面 | ティアード化されたサブ | マーケットプレイス | 定期寄付 | 1回限りの支払い |
|---|---|---|---|---|
| Stripe製品 | 複数の製品、製品あたり複数の料金 | サービスタイプあたり単一の製品 | 単一の製品、動的料金設定 | 単一の製品、固定料金 |
| 請求モード | subscription |
接続を伴うpayment |
subscription |
payment |
| ウェブフック複雑性 | 高い(ライフサイクルイベント) | 高い(接続イベント) | 中程度 | 低い |
| 通貨処理 | 地域別料金設定マトリックス | プロバイダーの通貨 | 寄付者の通貨 | 単一通貨 |
| トライアルサポート | はい、地域依存 | N/A | N/A | N/A |
| 按分 | はい、アップグレード時 | N/A | N/A | N/A |
| 払い戻し複雑性 | 按分計算 | プラットフォーム手数料の払い戻し | シンプルな全額払い戻し | シンプルな全額払い戻し |
| 顧客ポータル | 必須 | 不要 | 持っていると良い | 不要 |
| Stripe手数料(2025年) | 2.9% + 30¢ | 2.9% + 30¢ + 0.5% Connect | 2.9% + 30¢ | 2.9% + 30¢ |
FAQ
ティアード料金設定に対して何個のStripe製品を作成する必要がありますか?
ティアごとに1つの製品。つまり、Free、Basic、Pro、Premiumがある場合、それは4つの製品です。各製品には複数の料金があります。1つあたり1つの通貨と請求間隔の組み合わせがあります。月次と年次請求を含むProティア(10通貨全体で20個の価格オブジェクト)は、その単一の製品上にあります。たくさんのように聞こえるかもしれませんが、Stripeはこれをうまく処理し、カタログを整理したままにします。
地域別料金設定でStripeチェックアウトを使用できますか?
はい、ただしチェックアウトセッションを作成する前に顧客の地域を確定する必要があるため、正しい料金IDを渡すことができます。IP地理情報(Cloudflareヘッダー経由)を使用して通貨をあらかじめ選択してから、顧客に確認または変更させます。チェックアウト自動通貨に依存しないでください。どの料金を見るかについて管理が必要です。
Stripe Connect Expressアカウントとカスタムアカウントの違いは何ですか?
Expressアカウントを使用すると、Stripeはプロバイダーのオンボーディング、身元確認、およびダッシュボードを処理できます。カスタムアカウントは完全な制御を与えますが、これらすべてを自分で構築する必要があります。ほとんどのマーケットプレイスでは、Expressが正しい選択です。制御の喪失がカスタムのエンジニアリングコストを正当化した場合はありません。Expressアカウントはまた税務報告(米国の1099年)を自動的に処理し、これは大規模なコンプライアンスの勝利です。
失敗したサブスクリプション支払いを顧客を失わずに処理するにはどうすればよいですか?
3つの層を重ねます: Stripeのスマート再試行(ダッシュボードで有効)、invoice.payment_failedウェブフックによってトリガーされたカスタムダニングメール、キャンセル前のグレースピリオド。キャンセル前に14日間で3回の再試行を与えます。最初のメールは親切です(「あ、カードの有効期限が切れたかもしれません」)、2番目は緊急、3番目は最終警告です。支払い方法を更新できる顧客ポータルへの直接リンクを含めます。これだけで約30-40%の失敗した支払いを回復します。
Stripe Connectに対して別のウェブフックエンドポイントが必要ですか?
はい。プラットフォームイベントとConnect アカウントイベントは異なるウェブフック秘密鍵と異なるイベント構造を使用します。Connect イベントには、どの接続されたアカウントがイベントに関連するかを識別するaccountフィールドが含まれます。Stripeダッシュボードに2つのエンドポイントを登録してください: プラットフォームイベント用、Connect イベント用。この分離はデバッグを非常に簡単にします。
ゼロ小数通貨とは何で、なぜ気にかける必要がありますか?
ゼロ小数通貨(日本円やKRW(韓国ウォン))など。小数単位を使用しないでください。Stripeが「最小通貨単位の金額」と言うときは、USDの場合はセント(2900 = $29.00)ですが、JPYの場合は円(4200 = ¥4,200)です。USDと同じように100で乗算する場合、¥420,000ではなく¥4,200の代わりに請求してしまいます。通貨を変換する前に確認するヘルパー関数を常に使用します。Stripeはドキュメント内でゼロ小数通貨の公式リストを保守しています。
Stripe Billingの顧客ポータルを使用するか、自分で構築する必要がありますか?
特定のUI要件がない限り、サブスクリプション管理に顧客ポータルを使用します。プランの変更、キャンセル、支払い方法の更新、および請求書の履歴をすぐに処理します。ブランディングをカスタマイズし、どのアクションが許可されるかを構成できます。独自のポータルを構築することは、按分計算、支払い方法のトークン化、およびSCA/3D Secureフローを自分で処理することを意味します。ポータルは無料です。これはStripeサブスクリプション手数料に含まれています。
地域別料金設定と通貨処理をローカルでテストするにはどうすればよいですか?
Stripeのテストモードはすべての通貨をサポートしています。サポートする予定のある各通貨でテスト料金を作成してから、Stripe CLIを使用してローカルサーバーにウェブフックを転送します: stripe listen --forward-to localhost:3000/webhooks/stripe。ゼロ小数通貨テストの場合、JPY料金を作成して、本番環境に移行する前にウェブフックハンドラーログの金額を確認します。また、サポートされているすべての通貨に対してtoStripeAmountおよびfromStripeAmountを実行するテストスイートを保持しています。以上のことは1回以上の問題をキャッチしています。
サブスクリプションベースの製品を構築しており、請求アーキテクチャについてヘルプが必要な場合、またはStripeをヘッドレスCMSセットアップと統合している場合は、お問い合わせください。複数のヘッドレスCMSプロジェクトでこれらのパターンを構築しており、高コストな誤りをスキップするのに役立ちます。エンゲージメントモデルについては料金設定ページをご覧ください。プロジェクトベースの構築と継続的なアドバイザリーの両方を行います。