stripepayment linksinvoice settingspo numberb2b saasinvoluntary churn

Payment Links Couldn't Put a PO Number on a Subscription Invoice. As of October 28, They Can.

Stripe just let Checkout Sessions and Payment Links set tax IDs, PO numbers, and footers on subscription invoices — no Subscriptions API call required.

XY
3 November 2026 · 8 min read

If you sell a subscription through a Stripe Payment Link or a Checkout Session, you've probably run into this: a mid-market customer wants to pay, their AP team needs a PO number or your company's tax ID printed on the invoice before anyone will approve it, and there's no field for either one anywhere in the no-code flow. You could always get there — eventually — by waiting for the subscription to exist, then calling the Subscriptions API separately to patch it in. As of October 28, 2026, you don't have to. Stripe added account_tax_ids, custom_fields, description, and footer directly to subscription_data.invoice_settings on both Checkout Sessions and Payment Links, so the first invoice a subscription ever generates can carry that data from the moment it's created.

Key stat
18.4%
Share of B2B invoices that stall as an AP exception — missing or mismatched reference data is a leading cause
Source: Ardent Partners, "State of ePayables 2025"

What actually shipped on October 28

The change is additive, and it's narrow in exactly the right way. Stripe added four parameters to the subscription_data.invoice_settings hash on both Checkout.Session#create / update and PaymentLink#create / update: account_tax_ids, custom_fields, description, and footer. All four already existed as parameters on the Subscriptions API's own invoice_settings hash — nothing new is being invented here. What's new is where you're allowed to set them. Until this release, if you wanted a subscription's invoices to carry your tax registration number, a PO number in a custom field, a specific line description, or a footer disclaimer, and that subscription was created through a Checkout Session or a Payment Link rather than a direct Subscription.create call, you had no way to set those fields at creation time. You had to let the subscription come into existence first, then go back and patch it.

It shipped under API version 2026-10-28.endive — Stripe's standard dated channel, not the .preview channel reserved for features still subject to change. That distinction matters more than it sounds like it should: a preview parameter can still shift shape before it's final, while an Endive-channel parameter is meant to be built on in production immediately.

Why "patch it in later" was never a small inconvenience

Most teams using Checkout Sessions or Payment Links for subscription signup didn't build a manual Subscriptions.update call for invoice metadata because they enjoyed writing extra integration code. They built it because it was the only path available, and it came with a timing problem baked in. A Checkout Session in subscription mode creates the underlying Subscription object the moment the customer completes payment — and if that subscription bills immediately rather than starting with a trial, Stripe generates the first invoice right then, synchronously, as part of completing the checkout. Your own code only finds out any of this happened when the checkout.session.completed webhook arrives, seconds later at best, sometimes longer if your endpoint is slow or retried. By the time your handler calls the Subscriptions API to attach a PO number or a tax ID, that first invoice may already be finalized. Every subsequent invoice gets the field. The one invoice your customer's AP team is most likely to actually scrutinize — the first one, the one that proves you're a legitimate new vendor — doesn't.

We've written before about what happens when a net-terms invoice is missing the reference data an AP system expects: it doesn't bounce back with an error, it just sits in a queue, unpaid, until someone notices. A missing PO number or tax ID on invoice one doesn't usually kill a deal outright — but it's exactly the kind of avoidable defect that turns a new account's first 90 days into a collections problem instead of a clean start, and early-lifecycle churn is disproportionately expensive precisely because it happens before anyone on your side is watching closely.

Where the subscription is createdBefore Oct 28After Oct 28
Direct Subscriptions API callSet invoice_settings in the same create call — always workedNo change; same as before
Checkout Session (subscription mode)Create with no invoice_settings, wait for checkout.session.completed webhook, then call Subscriptions.update — first invoice may already be finalizedSet invoice_settings.subscription_data directly on Checkout.Session#create — first invoice is correct from the start
Payment LinkNo way to set per-link invoice metadata at all; had to patch every resulting subscription individually after the factSet invoice_settings.subscription_data once when creating or updating the link; applies to every invoice it generates

The catch on Payment Links specifically

A Payment Link is one URL, reused by however many customers click it. Whatever you put in custom_fields when you create or update that link gets applied to every invoice the link ever generates — it's static, not per-customer. That's genuinely useful if you run a dedicated Payment Link per product tier and just want a consistent tax ID or footer on every invoice that tier produces. It does nothing for a PO number, which is almost by definition different for every customer and every deal. If you're selling B2B through Payment Links and PO numbers are a recurring requirement, the realistic pattern is a Payment Link per customer or per contract — which plenty of sales-assisted, self-serve-adjacent SaaS teams already do for exactly this reason, since Stripe lets you set a link's price and now its invoice metadata independently of any other link you've created.

Checkout Sessions don't have this limitation, because you create a fresh one for every transaction from your own backend. If you already have the customer's PO number in hand at checkout time — because you collected it in a form field, or pulled it from a CRM record before redirecting to Stripe — you can now pass it straight into subscription_data.invoice_settings.custom_fields on that one session, and it lands on that one customer's invoice. No static link, no per-customer duplication.

B2B invoice processing, 2025
Invoices linked to a purchase order65.4%
Invoices that stall as an AP exception18.4%

Source: Ardent Partners, "State of ePayables 2025"

Read those two numbers together and the mechanism clicks into place. Roughly two-thirds of B2B invoices already carry a PO reference, which means AP systems at a huge share of your customers are built to expect one, not to tolerate its absence. Close to one in five invoices industry-wide stalls as an exception before it's even approved for payment — and reference-data mismatches, PO numbers chief among them, are consistently cited as a leading cause. None of that is specific to Stripe or to SaaS. It's just what happens when an invoice shows up without the metadata the receiving system was built around.

Who this actually changes anything for

Three shapes of team get real value out of this, and they're not identical:

  • Self-serve B2B SaaS selling through Payment Links, where setting up a per-deal link with the right tax ID and footer baked in replaces a manual follow-up email or a support ticket asking finance to fix an invoice after the fact.
  • Product-led SaaS whose signup flow runs through Checkout Sessions and already collects company details — a VAT number, a cost center, a PO reference — somewhere in that flow, but previously had to stash that data and apply it after the webhook fired. That data can now go straight onto the session that creates the subscription.
  • Teams that built the old webhook-patch workaround and have been living with occasional first-invoice defects as an accepted cost of the integration. For them, this isn't a new capability so much as the chance to delete a race condition they've been quietly working around for years.

If none of that describes you — if your invoices never carry a tax ID, custom field, or footer, or you create subscriptions exclusively through the Subscriptions API where this was always possible — the October 28 release changes nothing for your integration. That's a reasonable amount of the Stripe-using population. It's just not the point of this one.

What this doesn't fix

It doesn't collect the data for you. custom_fields on a Checkout Session is a slot for a PO number you already have — it's not a form field that asks the customer for one. If your signup flow doesn't currently capture a PO number, a cost center, or a billing contact anywhere, adding this parameter gives you a place to put that data once you have it, not a reason it'll suddenly start arriving. It also doesn't touch what happens to an existing subscription's invoice settings — this is additive to creation and update calls on the session or link itself; changing invoice metadata on a subscription that's already running still works the same way it always has, through the Subscriptions API or the Billing Portal.

And it doesn't make a Payment Link dynamic. If your actual problem is "every customer needs a different PO number on a link I want to reuse," this release doesn't solve that — it solves "I want every invoice from this specific link or session to carry this specific metadata," which is a narrower, more mechanical problem than full per-customer customization at a shared URL.

None of this moves a subscriber who's already decided to leave — that's a cancellation flow problem, which is what CancelFlow exists to solve. What it does move is a quieter failure point upstream of cancellation entirely: a new B2B subscriber whose first invoice gets kicked back by their own AP system before the relationship has even had a chance to start, turning what should have been a clean signup into a 60-day collections chase. If you're trying to separate how much of your early churn is a product problem versus a paperwork problem, our churn calculator is a reasonable place to start pulling that thread before you assume the worst about why a new account went quiet.

Frequently asked questions

What are Stripe's new invoice_settings parameters for Checkout Sessions and Payment Links?+

Four fields — account_tax_ids, custom_fields, description, and footer — nested under subscription_data.invoice_settings. They shipped October 28, 2026 on API version 2026-10-28 (Endive), a standard non-preview release, for both Checkout Session create and update and Payment Link create and update. They control the same invoice data the Subscriptions API has always exposed through invoice_settings — your account's tax IDs, up to custom reference fields like a PO number or cost center, a line description, and a footer message — except now you can set them at the point you create the Checkout Session or Payment Link instead of only through a separate Subscriptions API call afterward.

Can I set a different PO number for each customer using the same Payment Link?+

No. A Payment Link is a single, reusable URL — whatever you put in custom_fields when you create or update that link applies to every invoice generated from it, for every customer who pays through it. If different customers need different PO numbers on their invoices, you need a separate Payment Link per customer or per deal, or you need to move to a Checkout Session, which you create fresh for each transaction and can populate with that specific customer's PO number at creation time.

Does this fix the race condition where a Checkout Session's first invoice goes out before the PO number is attached?+

For new integrations built on top of this parameter, yes. Before October 28, the only way to get a PO number or tax ID onto an invoice generated by a Checkout-Session-created subscription was to wait for the checkout.session.completed webhook, then make a second call to the Subscriptions API to patch invoice_settings onto the subscription that already existed. If Stripe generated the first invoice immediately — which it does for subscriptions billed right away — that invoice could already be finalized before your webhook handler ran, shipping without the PO number your customer's AP system needed. Passing invoice_settings directly on Checkout Session creation removes that gap for the first invoice; webhook-based updates after the fact are still what you'd use to change those fields later, mid-subscription.

Is this feature in preview, or can I use it in production now?+

It's generally available, not a preview feature. It shipped under the 2026-10-28.endive API version — Stripe's standard dated release channel — rather than a .preview version, which is the designation Stripe uses for features still subject to change. You can adopt it in production once your account or your API requests are on that API version or later.

Try CancelFlow

Stop losing subscribers today

One script tag. One function call. A live cancellation flow in under 10 minutes.

Start free trial →
← All postsHome