Klarna vs Afterpay vs Affirm: BNPL Integration for Headless Checkout (2026)
Adding buy now pay later to a hosted checkout is a plugin and an afternoon. Adding it to a headless storefront is a different project, because in a custom checkout you own the flow that the plugin used to hide, and buy now pay later drags in more of that flow than any card processor does. The widget that shows a shopper their installment options is trivial. What is not trivial is the eligibility check that has to run before you render it, the session you have to create server side and reconcile against your order, the capture that happens on your schedule and not the shopper's, and above all the refund path, because a partial refund on a four installment plan is a genuinely different problem than a partial refund on a card. Klarna, Afterpay, and Affirm all solve the same shopper facing job, spread the cost, but they expose that job through APIs that assume different amounts of work on your side, and picking the wrong one for a headless build means discovering the mismatch at the point where refunds stop reconciling. This post compares them where a headless integration actually feels the difference and lays out the flow that keeps a custom checkout honest.
Klarna vs Afterpay vs Affirm: BNPL Integration for Headless Checkout (2026)
Putting buy now pay later on a hosted checkout is a plugin and a lunch break. Putting it on a headless storefront is a real integration, because a custom checkout means you own every step the plugin used to hide, and buy now pay later reaches into more of those steps than a card processor ever does. The installment widget itself is the trivial part. The work lives in the eligibility check that decides whether to even show the option, the payment session you create and reconcile server side, the capture that fires when you fulfill rather than when the shopper clicks pay, and the refund flow, which on an installment plan is a different animal than a card refund. Klarna, Afterpay, and Affirm all promise the shopper the same thing, spread the cost across payments, but they hand you that promise through APIs that assume very different amounts of work on your end. Choosing badly for a headless build usually means finding out at the worst moment, when a partial refund silently stops reconciling against the provider's ledger.
The Part That Is Actually Hard
On a hosted checkout the provider owns the whole flow, so the differences between these three barely surface. On a headless build the flow is yours, and it has four server side moments where the providers genuinely differ. The first is the presentment and eligibility step, where you ask the provider what installment plans apply to this cart, this amount, and this shopper's region before you render anything, because showing a plan the shopper cannot actually take is a conversion killer and sometimes a compliance problem. The second is session creation, where you open a payment session with the provider, hand it the order total and line items, and get back a token or redirect that authorizes the shopper. The third is capture, which in commerce rarely happens at click time; you authorize at checkout and capture at fulfillment, and each provider models the gap between those two differently. The fourth, and the one that separates a clean integration from a painful one, is the refund and dispute path.
Refunds are where buy now pay later stops resembling a card. When you refund part of a card charge, the processor reverses part of a single transaction and you are done. When you refund part of a four installment plan, the provider has to decide which installments to adjust, whether the shopper has already paid some of them, and how to rewrite the remaining schedule, and that logic lives on the provider's side but your checkout has to speak to it correctly and reconcile the result against your own order and your accounting. If your integration treats a buy now pay later refund like a card refund, it will appear to work in testing, where every order is refunded in full, and break in production the first time a shopper returns one item from a three item order paid in installments.
Where the Three Differ for a Headless Build
The shopper facing terms differ, but for an engineering decision the API surface and the settlement model matter more, because those are what your checkout has to integrate and reconcile against. This table is the decision that actually affects your build.
| Dimension | Klarna | Afterpay | Affirm |
|---|---|---|---|
| Core model | Multiple plans: pay in 4, pay later, financing | Pay in 4, fixed | Longer term financing plus pay in 4 |
| Typical order value fit | Broad, low to high | Lower value, impulse | Higher value, considered purchase |
| API style | Rich, session and order based, most surface area | Lean, checkout token based | Loan centric, checkout and financing APIs |
| Server side eligibility call | Yes, granular by plan and region | Minimal | Yes, tied to loan terms |
| Partial refund handling | Explicit line and amount aware | Amount based, simpler | Amount based, tied to loan adjustment |
| Settlement to merchant | Upfront, provider assumes risk | Upfront, provider assumes risk | Upfront, provider assumes risk |
| Best headless fit | Complex catalogs, mixed cart values, multi region | Simple pay in 4, lower ticket | High ticket, financing driven conversion |
The pattern under the table is a spectrum of how much the API asks of you. Afterpay is the leanest, a mostly checkout token based flow that suits a straightforward pay in 4 offering on lower ticket goods, and it is the fastest to integrate cleanly because it exposes the fewest moving parts. Klarna sits at the other end, with the richest and most granular API, session based and order aware, which is more to integrate but pays off when your catalog is complex, your cart values vary widely, or you sell across regions where the available plans differ and you need the eligibility call to be precise. Affirm is loan centric, built around financing longer term higher ticket purchases, and its API assumes you are integrating installment loans rather than a simple split, which is exactly right for high consideration goods and overkill for a twelve dollar impulse buy.
The Integration Shape
Regardless of provider, a headless buy now pay later integration should keep the same server authoritative shape, because the failure mode you are guarding against is a client that lies or drops. The browser renders the widget and collects the shopper's choice, but every decision that touches money, eligibility, session creation, capture, and refund, happens on your server against the provider's API, and your order is reconciled from webhooks, not from the shopper's redirect landing back on a success page. A shopper who closes the tab after authorizing but before your success handler runs must still end up with a correct order, and the only way to guarantee that is to treat the provider's server to server webhook as the source of truth and the browser redirect as a hint.
// Server side: create the BNPL session against your order, never trust the client for amounts
async function createBnplSession(order: Order, provider: BnplProvider) {
// 1. Eligibility first: ask the provider what plans apply before rendering anything
const plans = await provider.getEligiblePlans({
amount: order.total, // authoritative total from your cart, not the client
currency: order.currency,
region: order.shippingRegion,
items: order.lineItems, // Klarna uses line detail; others ignore extra fields
});
if (plans.length === 0) return { available: false };
// 2. Open a session tied to YOUR order id so webhooks can reconcile back to it
const session = await provider.createSession({
orderRef: order.id,
amount: order.total,
plans,
});
return { available: true, clientToken: session.clientToken, sessionId: session.id };
}
// Webhook is the source of truth. The browser redirect is only a hint.
async function onBnplWebhook(event: BnplWebhookEvent) {
const order = await orders.findByRef(event.orderRef);
switch (event.type) {
case "authorized":
await orders.markAuthorized(order.id, event.providerRef);
break;
case "captured":
await orders.markPaid(order.id, event.capturedAmount);
break;
case "refunded":
// Partial refunds: record the amount AND the provider's adjusted schedule ref
await orders.recordRefund(order.id, event.refundedAmount, event.providerRef);
break;
}
}
The refund handler is the piece worth dwelling on. Store the provider's reference for every refund and reconcile the refunded amount against the order rather than assuming a refund zeroed the whole thing, because on an installment plan the provider may have adjusted a schedule rather than reversed a charge, and your accounting has to reflect the amount actually returned. Getting webhook delivery right underneath all of this is its own discipline, one we covered in the webhook delivery reliability writeup, and buy now pay later raises the stakes because a missed capture or refund webhook is a money discrepancy, not just a stale status.
Multi Region and Multi Currency Wrinkles
If you sell across regions, the eligibility call stops being a nicety and becomes load bearing, because buy now pay later availability and the specific plans on offer vary by country and sometimes by the shopper's own history, and the provider is the only authority on what is actually available right now. Hard coding a plan set per region will drift out of date and show shoppers options they cannot take. Klarna's granular eligibility API is a real advantage here precisely because it is designed to answer that question per plan and per region, while a leaner provider may push more of that logic back onto you. This interacts directly with how you present prices across currencies, which we broke down in the cross border pricing writeup, because an installment amount shown in the wrong currency or an ineligible plan surfaced to the wrong region is the kind of checkout friction that quietly suppresses conversion in exactly the markets you were trying to grow.
Choosing One, or More Than One
For a single provider decision, match the API to your catalog rather than the brand to your taste. If you sell lower ticket goods and want the cleanest, fastest integration, Afterpay's lean pay in 4 flow is the least code and the least ongoing surface to maintain. If you sell high consideration, higher ticket items where financing is what actually converts the sale, Affirm's loan centric model is built for that and its heavier API earns its keep. If your catalog is broad, your cart values swing widely, or you operate across regions with different plan availability, Klarna's richer API and granular eligibility are worth the extra integration effort because they handle the complexity you would otherwise be hand rolling.
Plenty of merchants run more than one, and if you do, the discipline that saves you is a provider abstraction in your checkout so eligibility, session creation, capture, and refund go through one internal interface with a thin adapter per provider, rather than three parallel checkout paths that each reconcile differently. That is the same server authoritative pattern that keeps a card integration sane, extended to cover the installment schedule and refund semantics that make buy now pay later distinct, and it is the layer where a headless checkout either stays maintainable or turns into a reconciliation liability.
When This Applies to Your Stack
If you are adding buy now pay later to a headless storefront, the widget is not the project; the eligibility, capture, and refund logic in a checkout you own is. Choose Afterpay for lean low ticket pay in 4, Affirm for financing driven high ticket conversion, and Klarna when catalog complexity or multi region availability makes its granular API worth the extra work. Whichever you pick, keep every money touching decision on the server, reconcile from webhooks rather than browser redirects, and build the refund path to understand installment schedules rather than treating a partial refund like a card reversal, because that mismatch is the failure that hides through testing and surfaces in production.
Designing that checkout layer so it stays correct across providers, partial refunds, and multiple regions is the headless commerce integration work Contra Collective does when a custom storefront needs payments that reconcile cleanly rather than a widget that demos well and breaks on the first return.
FAQ
Why is BNPL harder to integrate in a headless checkout than a hosted one? On a hosted checkout the provider owns the flow, so the complexity is hidden. In a headless build you own the eligibility check, server side session creation, capture at fulfillment, and the refund path, and buy now pay later touches all four more than a card processor does. The refund logic in particular differs from cards because a partial refund adjusts an installment schedule rather than reversing a single charge.
Which BNPL provider is easiest to integrate for a headless build? Afterpay is generally the leanest, with a mostly checkout token based flow that suits a straightforward pay in 4 offering on lower ticket goods. It exposes the fewest moving parts, which makes it the fastest to integrate cleanly. Klarna has the richest API and asks the most of you, which pays off for complex or multi region catalogs.
How should partial refunds be handled with BNPL in a custom checkout? Do not treat a buy now pay later refund like a card refund. Send the refund to the provider, then record both the refunded amount and the provider's reference, and reconcile that amount against your order rather than assuming the whole plan was zeroed. The provider may adjust the remaining installment schedule instead of reversing a charge, so your accounting has to reflect the actual amount returned.
Should I trust the browser redirect or the webhook to confirm a BNPL order? The webhook. Treat the provider's server to server webhook as the source of truth for authorization, capture, and refund, and treat the browser redirect back to your success page as a hint only. A shopper who closes the tab after authorizing must still end up with a correct order, which is only guaranteed if reconciliation is webhook driven.
Can I offer more than one BNPL provider at checkout? Yes, and many merchants do to match different order values and shopper preferences. The key is a provider abstraction in your checkout so eligibility, session creation, capture, and refund flow through one internal interface with a thin adapter per provider, rather than maintaining separate checkout paths that each reconcile differently.
More from the lab.
Adobe's 275 Billion Dollar 2026 Holiday Forecast: Is Your Commerce Stack Ready for Peak Season
Adobe's 2026 holiday forecast puts US online sales at 275.1 billion dollars between November 1 and December 31, up 6.7 percent year over year. The bigger number in the report is not the top line: AI referred traffic to retail sites is projected to grow 130 percent, with spikes to 159 percent on Thanksgiving alone. Most teams are reading this as a marketing story. It is an infrastructure story.
Shopify Lets Meta's Muse Check Out, Amazon Blocks It: The Platform Split Over AI Shopping Agents
On September 22, Shopify and Meta announced that Muse, Meta's AI shopping agent, can search Shopify merchant catalogs and complete purchases through Shop Pay. Within days, Amazon blocked the same agent from its marketplace, citing unauthorized agent access, identity concealment, and credential collection. Two platforms, the same AI agent, and two opposite bets on what agentic commerce should look like.
Mastercard Agent Pay, Visa TAP, and ACP: The Agentic Payments Protocol Map for Merchants (October 2026)
On October 1, 2026, Mastercard added a probability score and a set of trust and intelligence signals to Agent Pay, its framework for telling issuers whether a transaction was actually initiated by an AI agent, built in partnership with agent identity provider Skyfire and with Cloudflare on the data side. The same day, trade press mapped out eight separate protocols now live in agentic commerce: MCP, A2A, ACP, UCP, AP2, TAP, Agent Pay, and MPP, backed by Anthropic, Google, OpenAI, Stripe, Shopify, Visa, and Mastercard respectively or in combination. None of them has lost. They are stacking, not competing, which is both good news and a real integration problem for anyone who is not Shopify.