Klarna Buy Now Pay Laterfor D365 F&O — The Right Approach
Klarna isn't a card processor. It's a fundamentally different payment model — async authorization, credit decisions, order-line requirements, capture-on-shipment rules. Building a native D365 connector for it requires rethinking everything we know about payment integration. Here's how we approached it, informed by the hard-won lessons from our CardPointe build.
Why This Is Different
Our CardPointe connector taught us how Microsoft's Payment SDK works — MEF discovery, GAC deployment, per-entity configuration. Those lessons saved us weeks on Klarna. But the payment model itself is where Klarna gets complex.
Traditional card connectors follow a simple pattern: authorize a dollar amount → capture it. Klarna flips this. The buyer chooses a financing option (Pay Later, Slice It, Pay Now), Klarna makes a credit decision, the merchant ships the goods, and only then does capture happen.
D365's payment framework was designed for the card model. Making it work with Klarna's BNPL flow means extending — and sometimes working around — that framework at nearly every step.
The Fundamental Difference
Card Processing vs. Buy Now Pay Later
Side-by-side: why you can't treat Klarna like a card processor.
Payment Flow
Traditional Card
Authorize → Capture (single step)
Klarna BNPL
Session → Authorize → Order → Capture (multi-step)
Consumer Decision
Traditional Card
Card issuer approves instantly
Klarna BNPL
Klarna makes a real-time credit decision for the buyer
Settlement
Traditional Card
Merchant receives funds in 1-2 days
Klarna BNPL
Klarna pays merchant upfront; collects from buyer over time
Checkout UX
Traditional Card
Card number entry on merchant site
Klarna BNPL
Klarna-hosted widget or redirect — buyer chooses pay later, slice it, or pay now
Risk
Traditional Card
Merchant bears chargeback risk
Klarna BNPL
Klarna assumes the credit risk — merchant gets paid regardless
Refunds
Traditional Card
Refund → card network → issuer → buyer (3-10 days)
Klarna BNPL
Refund → Klarna adjusts buyer's installment plan instantly
Standing on Shoulders
What CardPointe Taught Us
Five hard-won lessons from our CardPointe build — applied from day one on Klarna.
MEF [Export] Attribute
Microsoft's Payment SDK uses Managed Extensibility Framework. Without [Export(typeof(IPaymentProcessor))], the connector loads but is silently dropped.
Applied to Klarna: Applied from day one on DES.Klarna.Connector — no decompilation needed this time.
GAC Deployment Discipline
.NET loads from GAC before the file system. A stale GAC entry silently shadows new deployments.
Applied to Klarna: Build script includes automatic GAC uninstall → reinstall → IIS reset on every deploy.
Four-Location Sync
The connector DLL must exist in Connectors folder, WebRoot/bin, K: drive, and GAC — all identical.
Applied to Klarna: Deployment script copies to all four locations atomically with hash verification.
Schema-First SQL
D365 column names are non-obvious. Assumed names waste cycles on failing queries.
Applied to Klarna: Every D365 table query starts with schema introspection — no guessing.
Per-Legal-Entity Config
The connector DLL ships globally (ISV layer), but Payment Services config is manual per legal entity.
Applied to Klarna: Klarna deployment guide includes per-entity setup checklist — Klarna credentials, merchant ID, and payment journal mapping differ per legal entity.
Architecture
The Full Integration Stack
Four layers from D365 checkout to Klarna's API — with the same ISV-layer deployment model as CardPointe.
Sales Order / POS / eCommerce
Buyer selects "Pay with Klarna" at checkout. D365 calls the Klarna connector to create a payment session.
KlarnaPaymentService + Handler
X++ classes orchestrate the payment lifecycle — session creation, authorization callback, capture on invoice, refund on credit note. Maps D365 payment events to Klarna API calls.
DES.Klarna.Connector.dll
ISV-layer assembly implementing IPaymentProcessor with [Export] attribute. Handles REST communication, OAuth authentication, request/response mapping, and error handling.
Payments + Order Management
Two API surfaces: Payments API for session/authorization flow, Order Management API for capture/refund/cancel lifecycle. All REST, all JSON, all over TLS 1.2+.
The Klarna Payment Lifecycle in D365
Unlike card connectors, capture happens after shipment — not at order confirmation
API Surface
Klarna's Eight Integration Points
Two API surfaces — Payments API for checkout flow, Order Management API for post-purchase lifecycle.
/payments/v1/sessions
Initialize a Klarna payment session with order lines, locale, and purchase details
/payments/v1/authorizations/{token}/order
Convert an authorized session into a Klarna order — the buyer has committed
/ordermanagement/v1/orders/{id}/captures
Capture funds after shipping — Klarna pays the merchant
/ordermanagement/v1/orders/{id}/refunds
Full or partial refund — Klarna adjusts the buyer's installment plan
/ordermanagement/v1/orders/{id}/cancel
Cancel before capture — no charge to buyer, no settlement to merchant
/ordermanagement/v1/orders/{id}
Retrieve full order state — status, captures, refunds, remaining amount
/ordermanagement/v1/orders/{id}/authorization
Extend authorization or update order amount before capture
/ordermanagement/v1/orders/{id}/release-remaining-authorization
Release uncaptured authorization — free the buyer's credit line
The Hard Parts
Five Challenges That Make Klarna Different
Each one requires architectural decisions that don't exist in traditional card processing.
Async Authorization Flow
The Problem
Traditional connectors authorize synchronously — charge the card, get a response. Klarna's authorization is asynchronous: create session → redirect buyer → Klarna makes credit decision → callback with result.
Our Approach
We built a callback handler in X++ that listens for Klarna's authorization event, maps the result to D365's payment state machine, and updates the Sales Order payment status. The connector polls or receives webhooks — configurable per deployment.
Order Lines Requirement
The Problem
Card processors need one number: the total amount. Klarna requires full order line details — item name, quantity, unit price, tax rate, total amount, product URL — for every line item. This is fundamental to Klarna's credit decision and consumer-facing installment breakdown.
Our Approach
The X++ helper pulls SalesLine records, maps D365 fields to Klarna's order_lines schema (including tax calculation via D365's tax engine), and serializes to JSON. Discount lines, shipping charges, and rounding adjustments are handled as separate order lines with specific Klarna type codes.
Capture on Shipment, Not on Order
The Problem
D365's standard payment capture fires when the Sales Order is confirmed. Klarna requires capture only after goods are shipped — capturing before shipment violates Klarna's merchant agreement and consumer protection rules.
Our Approach
We decoupled capture from order confirmation using a Chain of Command (CoC) extension on SalesInvoiceJournalPost. Capture fires only when the packing slip or invoice posts with shipment confirmation — matching Klarna's "capture on fulfillment" model.
Partial Captures & Multi-Shipment
The Problem
A single Sales Order can ship in multiple batches. Each shipment needs a partial capture against the same Klarna order. The remaining authorization must stay open until the final shipment.
Our Approach
The connector tracks captured vs. remaining amounts per Klarna order ID. Each partial shipment triggers a partial capture. After the final shipment, the connector releases any remaining authorization to free the buyer's credit line.
Multi-Market, Multi-Currency
The Problem
Klarna operates differently across regions — different API endpoints, different payment methods (Pay Later, Slice It, Pay Now), different compliance requirements. A connector built for US won't work in EU without changes.
Our Approach
The connector's merchant property metadata includes region selection (NA/EU/OC), and the base URL, available payment methods, and locale handling adapt accordingly. Currency and locale are derived from the D365 legal entity, not hardcoded.
The Build
Full Project Scope
Larger than CardPointe — the async flow, order-line mapping, and multi-market support add significant surface area.
9
X++ Classes
PaymentService, Helper, FormHandler, WebhookListener, and more
6
Tables & EDTs
3 tables (session tracking, order mapping, webhook log), 3 EDTs
8
Forms & Extensions
3 forms, 5 form extensions (Sales Order, Invoice, POS)
8
API Endpoints
Session, Order, Capture, Refund, Cancel, Get, Update, Release
1
C# Assembly
DES.Klarna.Connector.dll — MEF-exported, OAuth-authenticated
1
Webhook Handler
HTTP endpoint for async authorization callbacks and settlement notifications
Scope Comparison: CardPointe vs Klarna
CardPointe (Card Processing)
7 X++ classes · 5 tables/EDTs · 7 forms
8 API endpoints · Sync auth flow
~146 hours estimated
Klarna (BNPL)
9 X++ classes · 6 tables/EDTs · 8 forms
8 API endpoints · Async auth + webhooks
~190 hours estimated
The 30% increase comes from async flow handling, order-line mapping complexity, capture-on-shipment logic, and multi-market support.
Accounting Impact
How Klarna Changes the GL Flow
With card payments, money flows directly: buyer's card → merchant's bank. With Klarna, there's an intermediary: Klarna pays the merchant and collects from the buyer over time. This changes how D365 posts journal entries.
On Capture
D365 debits Klarna Receivable (not Bank) and credits AR
On Settlement
Klarna remits funds → D365 debits Bank, credits Klarna Receivable, books Klarna fees
On Refund
D365 credits Klarna Receivable, debits AR. Klarna adjusts the buyer's installment plan.
Key difference from CardPointe: CardPointe posts directly to the bank account on capture. Klarna requires an intermediate Klarna Receivable GL account because settlement happens days later in a batch. The connector's journal posting logic must handle this two-step flow — and the reconciliation between Klarna's settlement reports and D365's Klarna Receivable balance.
The Bottom Line
Klarna integration for D365 isn't a variation of card processing — it's a different category of work. The async authorization, order-line requirements, capture-on-shipment model, and multi-market complexity make it fundamentally more challenging than traditional payment connectors.
But the CardPointe project gave us the infrastructure knowledge we needed: MEF discovery, GAC deployment, four-location sync, per-entity config. Those aren't Klarna-specific problems — they're D365 Payment SDK problems. Solving them once means every subsequent connector starts from a proven foundation.
The result: a native D365 connector that lets merchants offer Buy Now Pay Later without leaving their ERP, without third-party middleware, and without the accounting gaps that come from bolt-on integrations.
Need BNPL in Your D365 Environment?
We build native D365 payment connectors — Klarna, CardPointe, Stripe, or any gateway. From ISV-layer assembly to GL journal posting, fully integrated into your payment lifecycle.