0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Stripe で請求書ドラフトのまま止めて custom_fields に独自項目を反映させるまで

0
Last updated at Posted at 2026-05-25

Stripe でサブスクリプション請求や send_invoice を利用していると、次のような要件が出てくることがあります。

社内で採番した管理番号を、請求書に載せたうえで顧客に送付したい。一方で、Checkout を用いると、Stripe が生成する請求書が社内作業を待たずに自動的に finalize(発行)されてしまう。

この要件に対応しやすいのが Invoice の custom_fields と、ドラフトのまま自動発行を止める auto_advance: false です。以下では、draft で止める理由、Webhook と API をどう組み合わせるか、実装で外しやすい点を順にまとめます。

運用の前提: 確認者が行うのは、ドラフト請求書の内容確認と、問題なければ発行(finalize)の承認まで。それ以外——invoice.created 後の auto_advance: false や徴収まわりの整備、custom_fields への番号反映、承認後の finalizesend → 条件に応じた pay——はバックエンドが API で自動実行する想定です(Dashboard で手作業する前提ではありません)。

最初は Checkout を使おうとしていた

サブスクリプションや請求を Stripe で実装する場合、Checkout Session を最初に検討することは多いです。一方、社内で管理番号を振ってから請求書に載せるフローでは、請求書を draft のまま保持し、finalize の前に custom_fields を書く必要が出ます。

一般的な Checkout(サブスク+セッション完了時に即時決済まで進む構成)では、請求書がすみやかに finalize され支払いへ進みやすいため、この設計と相性が悪いです。Subscription API と請求書(Invoicing)を組み合わせ、invoice.created の Webhook で auto_advance: false を入れる構成へ寄せるのが現実的です。

実装の一例として、サブスクリプションを send_invoice で作成し、invoice.created の Webhook で請求書の徴収まわりや PDF 設定などをまとめて整える、という形もよく取られます。

注意: 2026 年 3 月時点の Stripe のドキュメント・挙動を前提とします。実装時は 公式ドキュメント を必ず確認してください。


要点

  • 管理番号を請求書に載せる → 多くの場合 custom_fields(PDF / Hosted Invoice Page に表示)
  • finalize 後は変更しにくい → draft のうちに書く
  • 新規サブスク+charge_automatically → 初回請求は即 finalize になりやすく、draft で触る猶予がないSubscription invoices)。send_invoiceauto_advance: false などの設計とセットで検討
  • 自動 finalize を止める → invoice.createdauto_advance: false
  • 明細行の追加は invoiceitems、顧客に見せないキーは metadata(役割が別)
  • 確認者は確認・発行承認まで。それ以外は API で自動(上記の運用前提)

運用上の処理の流れをフロー図にすると、次のとおりです。


用語と API の対応関係

「請求書に項目を追加したい」という要求は、Stripe 上では複数の API に分かれます。混同すると実装が複雑化しやすいため、先に対応関係を示します。

やりたいこと Stripe 上の主な手段 タイミング
管理番号を請求書に印字 custom_fields draft のみ(finalize 後は困難)
金額の行を足す invoiceitems.createinvoice に draft ID) finalize 前のみ
連携用キー(PDF に出さない) metadata(Invoice / Customer) API 向け

なぜ「発行後に追記」が難しいのか

サブスクリプション請求の Invoice は、いったん draft で作成されるところから始まります。ただし collection_method や初回/更新によって、draft のまま編集できる時間は同じではありません。一般論として open(発行済み)になると custom_fields を含め実質ロックに近いため、確認者が番号を振ってから PDF に載せるには、draft の間に custom_fields を書く必要があります。

新規サブスクの初回請求と collection_method(公式の finalize タイミング)

Stripe の Subscription invoices(New subscription invoices)では、サブスクリプション作成時に作られる請求書の扱いが collection_method ごとに次のように説明されています。

  • charge_automatically: 請求書をすぐに finalize し、顧客のデフォルト決済手段への請求に進みます。
  • send_invoice: finalize は最大で約 1 時間後(その間は請求書を編集できる、という説明)。

同ページの「Charge default payment method」には、初回請求は即 finalize され、finalize 前に初回請求を更新できる1 時間の猶予はないことも明記されています。

つまり新規サブスク+charge_automatically では、初回請求が即 open 側へ進み、draft のまま custom_fields を載せる時間が事実上取れないことがあります。要件が「初回の PDF にも管理番号を載せたい」であれば、send_invoice に寄せる、invoice.created で即 auto_advance: false など draft を維持する別策を講じる、公式が案内するトライアル等で初回請求の扱いを調整するなど、初回だけ挙動が違う前提で設計する必要があります。

更新請求と Webhook まわり

更新請求(例: billing_reasonsubscription_cycle)では、Subscription invoices ではしばらく draft のままになり、その後 finalize・徴収に進む、と説明されています。auto_advance が有効なままだと、draft が長く留まらず自動 finalize に進むリスクは引き続きあるため、invoice.createdauto_advance: false にする運用と相性がよい場面があります。

Webhook の遅延や障害があると、その間に自動 finalize が走るリスクがあるので、Handler は速やかに 2xx を返し、更新処理は何度来ても同じ結果になるよう(冪等に近く)しておくと安全です。


draft を止める: auto_advance: false

draft の Invoice に auto_advance: false を入れると、自動 finalize の進行を抑止できます。

方法 内容
Webhook invoice.created かつ status === 'draft' のとき invoices.updateauto_advance: false
ダッシュボード等 請求書をレビュー用に保留(公式)

コード例(Node.js / stripe)

本番ではリクエストボディの生データで 署名を検証してから処理します(stripe.webhooks.constructEvent)。Stripe は失敗時に同じイベントを再送するため、処理完了後は 2xx を返し、invoices.update は何度実行してもよい形にしておきます。

import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)

export async function handleInvoiceCreated(invoice: Stripe.Invoice) {
  if (invoice.status !== 'draft') return

  await stripe.invoices.update(invoice.id, {
    auto_advance: false,
  })
}

実装によっては、同じ invoices.update に PDF・税・支払期限・徴収方法などもまとめて載せます。


全体の流れ

確認・承認以外は API で自動とした場合の、処理の順序の一例です。

誰が 何をするか
1 Webhook(自動) invoice.createdauto_advance: false 等で draft を保持
2 バックエンド(自動) 必要なら invoiceitems、採番・取り込み後に custom_fields 更新
3 確認者 ドラフトの内容確認と発行承認(自社画面)
4 バックエンド(自動) finalizesend → 課金設計に応じて pay

draft の特定(自動処理で誤更新しないために): invoices.listsubscription + status: 'draft' などで絞り、請求ラインの period.end(Unix 秒)が対象の請求期間と一致するものを選ぶ、といったルールを一文で決めておくとよいです。

pay の有無:

パターン pay
カードで発行後に徴収する設計 呼ぶことが多い(Pay an invoice
日本の銀行振込(仮想口座・請求書フロー) 呼ばないことが多い(Bank transfer (JP)

custom_fields の要点

  • 最大 4 件、名前 40 文字・値 140 文字まで(Invoice オブジェクト
  • draft のみ更新可能。PDF と Hosted Invoice Page の両方に出る前提でラベル(例: 管理番号)を決める

マージしながら更新する例(Node.js)

既存の custom_fields を消さないよう、retrieve → マージ → update します。

import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)

async function setInternalMgmtNumberOnDraft(
  invoiceId: string,
  fieldName: string,
  fieldValue: string,
) {
  const inv = await stripe.invoices.retrieve(invoiceId)

  if (inv.status !== 'draft') {
    throw new Error(`Invoice is not draft: ${inv.status}`)
  }
  const existing = inv.custom_fields ?? []
  const others = existing.filter((f) => f.name !== fieldName)
  const custom_fields = [...others, { name: fieldName, value: fieldValue }].slice(
    0,
    4,
  )
  return stripe.invoices.update(invoiceId, { custom_fields })
}

await setInternalMgmtNumberOnDraft('in_xxx', '管理番号', 'INT-2026-0042')

テスト

Stripe CLI の stripe listen --forward-to で Webhook をローカルに転送する方法は 公式 を参照。テストモードで Subscription を作り、実際に invoice.created が届くところまで通すのが確実です。


付録: 一覧から一括で custom_fields を載せる場合

  1. 社内キーと Stripe Customer を対応付ける(Customer metadata がよく使われる)
  2. 対象期間の draft Invoice を特定する(period.end 等)
  3. 行ごとに invoices.updatecustom_fields
  4. 結果をログ・通知で返す

秘密鍵・Webhook シークレット・ファイル経路の認可は本番前に設計・レビューしてください。


まとめ

  • 管理番号 → custom_fields + draft
  • 新規サブスクの初回+charge_automatically → 公式どおり即 finalize になり、draft で custom_fields を書く時間が取れないことがある → send_invoice や抑止策を設計に含める
  • 自動発行の抑止 → invoice.createdauto_advance: false(署名検証・2xx・再送を意識)
  • 確認者は確認・承認まで、finalize / send / pay は承認後に API で自動
  • Checkout 一択は draft 猶予の設計と相性が悪いことが多い → Invoicing 寄りの構成を検討

参考リンク(Stripe 公式)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?