Stripeでは、「10ユーザーまでは固定で5,000円、それを超えた場合は1ユーザーあたり400円」のような、複雑な料金体系を実装することができます。
また、「15ユーザーまでは単価50円+固定で100円、ただし16ユーザー目以降は単価45円と追加で固定90円で計算する」のような、より複雑なケースについてもサポートしています。
これらの料金体系をStripeでは、「段階的な料金」そして「数量ベースの料金」とよんでいます。
APIで料金データを取得する場合の注意点
PricesのList APIでは「段階的な料金」または「数量ベースの料金」を取得できない
これらの複雑な料金体系では、PriceのList APIだけでデータを取得することができません。
const {data: priceDatas} = await stripe.prices.list({
product: 'prod_xxx'
})
[
{
"id": "price_xxxxx",
"object": "price",
"active": true,
"billing_scheme": "tiered",
"created": 1644979081,
"currency": "jpy",
"livemode": false,
"lookup_key": null,
"metadata": {},
"nickname": "段階的な料金",
"product": "prod_xxxx",
"recurring": {
"aggregate_usage": null,
"interval": "month",
"interval_count": 1,
"trial_period_days": null,
"usage_type": "licensed"
},
"tax_behavior": "inclusive",
"tiers_mode": "graduated",
"transform_quantity": null,
"type": "recurring",
"unit_amount": null,
"unit_amount_decimal": null
}
]
上記のサンプルのように、価格に関するデータが欠落した状態となります。
対応: PricesのRetrieve APIを利用して詳細を取得する
この対応として、Retrieve APIを利用する方法を紹介します。
const {data: priceDatas} = await stripe.prices.list({
product: 'prod_xxx'
})
+ const prices = await Promise.all(priceDatas.map(async price => {
+ return stripe.prices.retrieve(price.id, {
+ expand: ['tiers']
+ })
+ }))
Retrieve APIのexpand
にtiers
を指定することで、料金データの詳細を取得できます。
[
{
"id": "price_xxxxx",
"object": "price",
"active": true,
"billing_scheme": "tiered",
"created": 1644979081,
"currency": "jpy",
"livemode": false,
"lookup_key": null,
"metadata": {},
"nickname": "段階的な料金",
"product": "prod_xxxx",
"recurring": {
"aggregate_usage": null,
"interval": "month",
"interval_count": 1,
"trial_period_days": null,
"usage_type": "licensed"
},
"tax_behavior": "inclusive",
+ "tiers": [
+ {
+ "flat_amount": null,
+ "flat_amount_decimal": null,
+ "unit_amount": 200,
+ "unit_amount_decimal": "200",
+ "up_to": 10
+ },
+ {
+ "flat_amount": null,
+ "flat_amount_decimal": null,
+ "unit_amount": 190,
+ "unit_amount_decimal": "190",
+ "up_to": 50
+ },
+ {
+ "flat_amount": null,
+ "flat_amount_decimal": null,
+ "unit_amount": 185,
+ "unit_amount_decimal": "185",
+ "up_to": null
+ }
+ ],
"tiers_mode": "graduated",
"transform_quantity": null,
"type": "recurring",
"unit_amount": null,
"unit_amount_decimal": null
}
]
APIのパフォーマンスには要注意
ただし、上記のサンプルでは、PriceごとにRetrieve APIを呼び出すため、APIのレスポンスが遅くなる可能性があります。
下の例では、tiers_mode
を持たないデータではAPI呼び出しを省略する実装を追加しています。
const prices = await Promise.all(priceDatas.map(async price => {
+ if (!price.tiers_mode) return price
return stripe.prices.retrieve(price.id, {
expand: ['tiers']
})
}))
もし取得が必要な料金の数が多い場合や、APIパフォーマンスを重要視したい場合は、外部のDBを用意することも検討できます。
その場合、Stripe側でWebhookを利用してデータの同期を行う運用をお勧めします。
終わりに
Stripeを利用することで、ユーザー数や利用数に応じた段階的・数量ベースの価格設定を行うことができます。
ただし、今回のように、その設定内容をAPIから取得し、操作するためにはすこし工夫が必要になるケースも存在します。
今後もユースケースだけでなく、より踏み込んだ実装に関するTipsもお届けしてまいります。