Back to Blog
BNPL IntegrationApril 19, 202612 min read

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.

D365 Frontend

Sales Order / POS / eCommerce

Buyer selects "Pay with Klarna" at checkout. D365 calls the Klarna connector to create a payment session.

X++ Form ExtensionPayment Services FormCheckout Widget
X++ Runtime

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.

KlarnaPaymentServiceKlarnaPaymentHelperKlarnaFormHandler
C# Connector

DES.Klarna.Connector.dll

ISV-layer assembly implementing IPaymentProcessor with [Export] attribute. Handles REST communication, OAuth authentication, request/response mapping, and error handling.

MEF [Export]IPaymentProcessorHttpClientOAuth 2.0
Klarna API

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+.

REST/JSONTLS 1.2+OAuth 2.0Idempotency Keys

The Klarna Payment Lifecycle in D365

Sales Order
Create Session
Buyer Authorizes
Klarna Approves
Order Created
Goods Shipped
Capture Fired
Settlement

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.

POSTCreate Session

/payments/v1/sessions

Initialize a Klarna payment session with order lines, locale, and purchase details

POSTCreate Order

/payments/v1/authorizations/{token}/order

Convert an authorized session into a Klarna order — the buyer has committed

POSTCapture

/ordermanagement/v1/orders/{id}/captures

Capture funds after shipping — Klarna pays the merchant

POSTRefund

/ordermanagement/v1/orders/{id}/refunds

Full or partial refund — Klarna adjusts the buyer's installment plan

POSTCancel Order

/ordermanagement/v1/orders/{id}/cancel

Cancel before capture — no charge to buyer, no settlement to merchant

GETGet Order

/ordermanagement/v1/orders/{id}

Retrieve full order state — status, captures, refunds, remaining amount

PATCHUpdate Order

/ordermanagement/v1/orders/{id}/authorization

Extend authorization or update order amount before capture

POSTRelease Auth

/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.

Challenge #1

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.

Challenge #2

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.

Challenge #3

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.

Challenge #4

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.

Challenge #5

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.