企業のデジタル化が進む中、ECサイトやWebサービスの「海外展開」や「グローバル化」に対する関心が近年高まってきています。
Stripeが公開しているレポートでは、企業の 66% が「今後 2 年以内に他国への展開を計画」 していることが明らかになりました。
Stripeを利用している場合、「日本円で、海外からの注文を受け付ける」または「現地の通貨で注文を受け付ける」の2つで海外からの売り上げを獲得することができます。
1: 日本円で、海外からの注文を受け付ける
この方法では、Webサイトなどは多言語化しつつも、決済に利用する通貨は日本円のままでサービスを提供します。そのため、サービス提供者が受け取る売り上げ額は、為替レートの影響をうけることはありません。ただし顧客から見た場合、サービスに支払う金額が都度変化するため、為替レートの変動が激しい場合通貨圏からは避けられる可能性があります。
2: 現地の通貨で注文を受け付ける
もう一つの選択肢は、その国・地域の通貨でサービスを提供することです。この方法を取ることで、利用者は為替レートの影響をうけることなく、また注文や請求のたびに「今回はいくらの支払いになるか」を計算・予測する必要もなくなります。
Stripeでは、商品に対して複数の価格を設定できます。そのため、提供を行うと決めた通貨について、料金データを追加することで準備ができます。
また、Stripe Checkout / Payment Links / Elementsなどが提供するUIは、訪問者のIPアドレスなどを基に表示する言語を自動で変更します。
APIパラメータを利用してカスタマイズする方法を、Qiitaで紹介していますので、こちらもぜひご覧ください。
外貨で決済を得た場合、日本円に替える必要がある
グローバルに注文・申し込みを受け付ける、「為替レートの影響」を考慮する必要があります。先に紹介した2つの方法どちらについても、「顧客が支払う金額」もしくは「受け取る売上金」どちらかが為替レートの影響を受けます。
また、会計処理を行う場合には、売上発生時や入金時についても日本円に換算して計上する必要があるため、通常よりも作業量が増加する点にも注意が必要です。
Stripeを使った場合の、外貨取引の取り扱い
Stripeを利用している場合、ドキュメントにて為替レートの計算方法を次のように紹介しています。
通常はサードパーティのサービスプロバイダーから提供される価格データに基づいた市場中央値を適用します。市場中央値とは、通貨の購入価格と販売価格の平均です。
https://stripe.com/docs/currencies/conversions?locale=ja-JP
Stripe内部で通貨の換算を行う場合、 決済額の2% の通貨換算手数料が発生する点にも留意が必要です。
取引ごとの為替レートを調べる方法
実際の取引で、どのように・どれくらいのレートで換算が行われたかを調べてみましょう。
Stripeの場合、ダッシュボードまたはAPIから為替レートを確認できます。
ダッシュボードから確認する
Stripeダッシュボードでは、各支払い詳細ページを利用します。支払いの詳細ページの中で、為替レート・通貨換算情報も確認することができます。
通貨換算が行われている支払いだけを見るため、支払い一覧ページで[通貨]によるフィルタを行うことをおすすめします。
https://dashboard.stripe.com/test/payments?status[0]=successful¤cy=usd
また、2023/11/24現在ベータ提供中のWorkbenchを利用することで、為替レートや支払い手数料などの情報を確認できる「Balance Transactionオブジェクト]()を直接見ることもできます。
この場合、"exchange_rate"
の値が為替レートとなります。
Workbenchのベータ版は、以下のURLから利用申請が可能です。
https://workbench.stripe.dev/workbench
APIを利用して数値を取得する
会計システムや自社の分析基盤など、外部のシステムにデータを取り込みたい場合、StripeのAPIを利用して取得することもできます。
この場合、Balance Transaction API
を利用します。
const balanceTransaction = await stripe.balanceTransactions.retrieve('ch_から始まるCharge ID')
Chargeのデータを組み合わせることで、「顧客から受け取った、現地通貨での売上高」と「日本円に通貨換算された後の売上高」両方を見ることができます。
const chargeId = 'ch_xxxx'
const charge = await stripe.charges.retrieve(chargeId, {
expand: ['balance_transaction']
})
const balance = charge.balance_transaction as Stripe.BalanceTransaction
const messages = [
`Charge amount: ${charge.amount.toLocaleString()} ${charge.currency.toLocaleUpperCase()}`,
`Balance transaction amount: ${balance.amount.toLocaleString()} ${balance.currency.toLocaleUpperCase()}`,
`Exchange rate: ${balance.exchange_rate}`,
]
console.log(messages.join('\n'))
このコードを実行すると、次のように現地通貨と日本円それぞれでの金額が表示されます。
Charge amount: 8,000 USD
Balance transaction amount: 11,732 JPY
Exchange rate: 1.46651
日本円で登録する必要があるデータなどは、このようにBalance Transactionの値を利用して登録しましょう。
Payment IntentsやInvoicesからから、Balance Transactionを取得する
Payment IntentsやInvoicesを利用している場合、expand
パラメータを利用することで、まとめて取得することも可能です。
Payment Intents
- const paymentIntent = await stripe.paymentIntents.retrieve('pi_xxx')
+ const paymentIntent = await stripe.paymentIntents.retrieve('pi_xxx, {
+ expand: ['charge.balance_transaction']
+ })
Invoices
- const invoice = await stripe.invoices.retrieve('in_xxx')
+ const invoice = await stripe.invoices.retrieve('in_xxx', {
+ expand: ['charge.balance_transaction',]
+ })
Webhookを利用してデータを処理する
APIを都度呼び出すのではなく、Webhookで自動化もできます。この場合、charges.succeeded
イベントを利用しましょう。
app.post('/webhook', async context => {
const stripe = new Stripe('sk_test_xxxx', {
apiVersion: '2023-10-16'
})
const signature = context.req.raw.headers.get("stripe-signature");
try {
if (!signature) {
return context.text("", 400);
}
const body = await context.req.text();
const event = await stripe.webhooks.constructEventAsync(
body,
signature,
'whsec_xxxxxxx',
undefined,
Stripe.createSubtleCryptoProvider()
);
if (event.type === "charge.succeeded") {
const charge = event.data.object
// ここに実装する
}
return context.text("", 200);
} catch (err) {
const errorMessage = `⚠️ Webhook signature verification failed. ${err instanceof Error ? err.message : "Internal server error"}`
console.log(errorMessage);
return context.text(errorMessage, 400);
}
})
Webhookイベントでは、expand
してデータを受け取ることはできません。そのため、Balance Transaction API
を呼び出してデータを取得しましょう。
app.post('/webhook', async context => {
const stripe = new Stripe('sk_test_xxxx', {
apiVersion: '2023-10-16'
})
const signature = context.req.raw.headers.get("stripe-signature");
try {
if (!signature) {
return context.text("", 400);
}
const body = await context.req.text();
const event = await stripe.webhooks.constructEventAsync(
body,
signature,
'whsec_xxxxxxx',
undefined,
Stripe.createSubtleCryptoProvider()
);
if (event.type === "charge.succeeded") {
const charge = event.data.object
+ if (charge.balance_transaction) {
+ const balanceTransactionId = charge.balance_transaction.id
+ const balance = await stripe.balanceTransactions.retrieve(balanceTransactionId)
+ console.log(`Charge amount: ${charge.amount} ${charge.currency.toLocaleUpperCase()}`)
+ console.log(`Balance transaction amount: ${balance.amount} ${balance.currency.toLocaleUpperCase()}`)
+ console.log(`Exchange rate: ${balance.exchange_rate}`)
+ }
}
return context.text("", 200);
} catch (err) {
const errorMessage = `⚠️ Webhook signature verification failed. ${err instanceof Error ? err.message : "Internal server error"}`
console.log(errorMessage);
return context.text(errorMessage, 400);
}
})
現地法人を立ち上げて、為替レートの変化に対応する
ここまで取引ごとの為替レートを調べる方法を紹介しました。最後に、為替レートの影響をより少なくする方法を1つ紹介します。
為替レートの変動が激しい場合、その上下がビジネスの収益性に影響を与えます。そのため、取引量・決済額が多い国・地域によっては、「現地法人を立ち上げて、現地の通貨Stripeから入金を受ける」方法も選択肢として挙がります。この方法であれば、為替レートの状況を見ながら、日本円に替えるタイミングを検討することができますし、現地法人を用意することで、決済の承認率(オーソリ率)が高まる可能性もあがります。
Stripeでは、アメリカ・デラウェア州に法人を作ることができるサービス、「Stripe Atlas」を提供しています。
このサービスを利用することで、簡単に現地法人や現地の銀行口座を手に入れることができます。
Atlasの利用方法については、Stripeのドキュメントをご確認ください。
Stripeで、決済や請求・サブスクリプションの「バックオフィス業務」も効率化・自動化しよう
このようにStripeでは、決済やサブスクリプションの組み込みだけでなく、バックオフィス業務の効率化やカスタマイズも可能です。
また、レポーティングや分析・データウェアハウスまたは外部システムへの連携などもシームレスに行えるため、「決済・注文・サブスクリプション申し込みの受け付けを終えた後」についても効率化や改善・自動化できます。
https://stripe.com/jp/use-cases/finance-automation
「バックオフィス業務の自動化・効率化」に興味がある方は、以下のドキュメントから詳細を確認してみましょう。