Klarna
Accept payments with Klarna. Use this skill when the project needs to integrate Klarna for buy-now-pay-later, installment plans, pay-in-30-days, or direct payments. Covers Klarna Payments API, Klarna Checkout, hosted payment page, order management, webhooks, and settlement.
You are a payments specialist who integrates Klarna into projects. Klarna is a
buy-now-pay-later (BNPL) provider that also offers direct payments, installment
plans, and a full hosted checkout. Klarna takes on the credit risk — merchants
get paid upfront regardless of the customer's payment schedule.
## Key Points
- Portal: `portal.playground.klarna.com`
- API: `api.playground.klarna.com`
- Test persona for US: use any name/address, Klarna auto-approves in playground
- Test with different countries to see available payment methods change
- Capture orders promptly — Klarna authorizations expire (typically 28 days)
- For digital goods, capture immediately after order placement
- Always include `order_lines` with accurate item details — Klarna uses them for risk assessment
- Use `merchant_reference1` to link Klarna orders to your internal order IDs
- Provide accurate `purchase_country` — it determines which payment methods appear
- Handle `fraud_risk.stopped` — Klarna may reject orders after initial approval
- Test with multiple countries in playground to verify localized payment methods
- Not capturing orders — Klarna will auto-release the authorization and you lose the sale
## Quick Example
```typescript
await klarnaRequest('POST', `/ordermanagement/v1/orders/${klarnaOrderId}/cancel`);
```skilldb get payment-services-skills/klarnaFull skill: 286 linesKlarna Payment Integration
You are a payments specialist who integrates Klarna into projects. Klarna is a buy-now-pay-later (BNPL) provider that also offers direct payments, installment plans, and a full hosted checkout. Klarna takes on the credit risk — merchants get paid upfront regardless of the customer's payment schedule.
Core Philosophy
Klarna pays you upfront
When a customer chooses "Pay in 3" or "Pay later", Klarna pays the merchant immediately. Klarna collects from the customer over time. This eliminates credit risk for the merchant.
Two integration paths
Klarna Payments embeds Klarna as a payment option alongside other methods. Klarna Checkout is a full hosted checkout that handles the entire purchase flow. Choose Payments for flexibility, Checkout for speed.
Orders must be acknowledged and captured
Klarna separates authorization from capture. You must capture (acknowledge the order) when you ship goods. For digital goods, capture immediately.
Setup
API credentials
Klarna uses HTTP Basic Auth with your API credentials (username/password) from the Klarna Merchant Portal. There is no official Node.js SDK — use HTTP directly or a wrapper library.
const KLARNA_API_BASE = process.env.KLARNA_ENV === 'production'
? 'https://api.klarna.com'
: 'https://api.playground.klarna.com';
const KLARNA_AUTH = Buffer.from(
`${process.env.KLARNA_USERNAME}:${process.env.KLARNA_PASSWORD}`
).toString('base64');
async function klarnaRequest(method: string, path: string, body?: object) {
const res = await fetch(`${KLARNA_API_BASE}${path}`, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${KLARNA_AUTH}`,
},
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`Klarna ${res.status}: ${await res.text()}`);
return res.status === 204 ? null : res.json();
}
Key Techniques
Klarna Payments — Create a session
const session = await klarnaRequest('POST', '/payments/v1/sessions', {
purchase_country: 'US',
purchase_currency: 'USD',
locale: 'en-US',
order_amount: 5000, // $50.00 in minor units
order_tax_amount: 0,
order_lines: [
{
name: 'Pro Plan — Monthly',
quantity: 1,
unit_price: 5000,
total_amount: 5000,
tax_rate: 0,
total_tax_amount: 0,
},
],
});
// Return session.client_token and session.payment_method_categories to frontend
Frontend — Klarna Payments widget
<script src="https://x.klarnacdn.net/kp/lib/v1/api.js"></script>
<div id="klarna-container"></div>
<script>
Klarna.Payments.init({ client_token: clientToken });
// Load the widget for a specific payment method
Klarna.Payments.load(
{
container: '#klarna-container',
payment_method_category: 'pay_later', // or 'pay_over_time', 'direct_debit'
},
(res) => {
if (res.show_form) {
// Widget loaded successfully
}
}
);
// When user clicks "Place Order"
async function authorize() {
Klarna.Payments.authorize(
{ payment_method_category: 'pay_later' },
{
purchase_country: 'US',
purchase_currency: 'USD',
locale: 'en-US',
order_amount: 5000,
order_tax_amount: 0,
order_lines: [
{
name: 'Pro Plan — Monthly',
quantity: 1,
unit_price: 5000,
total_amount: 5000,
tax_rate: 0,
total_tax_amount: 0,
},
],
},
async (res) => {
if (res.approved) {
// Send res.authorization_token to your server to place the order
await fetch('/api/klarna/place-order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ authorizationToken: res.authorization_token }),
});
}
}
);
}
</script>
Place an order (server-side)
const order = await klarnaRequest(
'POST',
`/payments/v1/authorizations/${authorizationToken}/order`,
{
purchase_country: 'US',
purchase_currency: 'USD',
locale: 'en-US',
order_amount: 5000,
order_tax_amount: 0,
order_lines: [
{
name: 'Pro Plan — Monthly',
quantity: 1,
unit_price: 5000,
total_amount: 5000,
tax_rate: 0,
total_tax_amount: 0,
},
],
merchant_reference1: orderId,
merchant_urls: {
confirmation: 'https://yourdomain.com/confirmation',
notification: 'https://yourdomain.com/api/klarna/webhook',
},
}
);
// Store order.order_id for capture/refund
Capture an order (on fulfillment)
await klarnaRequest('POST', `/ordermanagement/v1/orders/${klarnaOrderId}/captures`, {
captured_amount: 5000,
description: 'Shipped order',
order_lines: [
{
name: 'Pro Plan — Monthly',
quantity: 1,
unit_price: 5000,
total_amount: 5000,
tax_rate: 0,
total_tax_amount: 0,
},
],
});
Refund a capture
await klarnaRequest('POST', `/ordermanagement/v1/orders/${klarnaOrderId}/refunds`, {
refunded_amount: 5000,
description: 'Customer requested refund',
order_lines: [
{
name: 'Pro Plan — Monthly',
quantity: 1,
unit_price: 5000,
total_amount: 5000,
tax_rate: 0,
total_tax_amount: 0,
},
],
});
Cancel an uncaptured order
await klarnaRequest('POST', `/ordermanagement/v1/orders/${klarnaOrderId}/cancel`);
Webhook Processing
| Event | Action |
|---|---|
order.approved | Order authorized, ready to capture |
order.captured | Funds captured, confirm fulfillment |
order.cancelled | Order cancelled |
order.refunded | Refund processed |
fraud_risk.stopped | Klarna rejected the order |
dispute.created | Chargeback initiated |
export async function POST(req: Request) {
const body = await req.json();
// Klarna webhooks are verified by registering a webhook URL in the portal
// and optionally checking the Klarna-Idempotency-Key header
switch (body.event_type) {
case 'order.approved':
// For digital goods, capture immediately
await captureOrder(body.event_data.order_id);
break;
case 'order.captured':
await markOrderFulfilled(body.event_data.order_id);
break;
case 'fraud_risk.stopped':
await cancelInternalOrder(body.event_data.order_id);
break;
case 'dispute.created':
await handleDispute(body.event_data.order_id);
break;
}
return new Response('OK', { status: 200 });
}
Testing
Klarna playground environment:
- Portal:
portal.playground.klarna.com - API:
api.playground.klarna.com - Test persona for US: use any name/address, Klarna auto-approves in playground
- Test with different countries to see available payment methods change
Best Practices
- Capture orders promptly — Klarna authorizations expire (typically 28 days)
- For digital goods, capture immediately after order placement
- Always include
order_lineswith accurate item details — Klarna uses them for risk assessment - Use
merchant_reference1to link Klarna orders to your internal order IDs - Provide accurate
purchase_country— it determines which payment methods appear - Handle
fraud_risk.stopped— Klarna may reject orders after initial approval - Test with multiple countries in playground to verify localized payment methods
Anti-Patterns
- Not capturing orders — Klarna will auto-release the authorization and you lose the sale
- Omitting
order_linesor using placeholder data — increases decline rates - Assuming all payment methods are available everywhere — availability varies by country
- Ignoring Klarna's fraud rejection webhooks — you ship goods that Klarna won't pay for
- Using Klarna for subscription billing without separate authorization per cycle
- Capturing more than the authorized amount — this will fail
- Not testing with the playground environment — live credentials have real financial impact
Install this skill directly: skilldb add payment-services-skills
Related Skills
Lemonsqueezy
Accept payments with Lemon Squeezy as merchant of record. Use this skill when the project needs to integrate Lemon Squeezy for SaaS subscriptions, digital product sales, license key management, checkout overlay, tax compliance, or affiliate programs. Covers the Lemon Squeezy API, checkout, subscriptions, license keys, webhooks, and Lemon.js.
Mollie
Accept payments with Mollie. Use this skill when the project needs to integrate Mollie for European payments, iDEAL, Bancontact, SEPA, Klarna, subscriptions, payment links, or multi-currency checkout. Covers the Mollie API, payments, subscriptions, mandates, refunds, and webhooks. Popular in Netherlands, Belgium, Germany, and across Europe.
Paddle
Accept payments with Paddle as merchant of record. Use this skill when the project needs to integrate Paddle for subscription billing, one-time payments, checkout overlay, tax compliance, invoicing, or global payment processing where Paddle handles tax, compliance, and payouts. Covers Paddle Billing API, checkout, subscriptions, transactions, webhooks, and Paddle.js.
Paypal
Accept payments with PayPal. Use this skill when the project needs to integrate PayPal for checkout, subscriptions, one-time payments, PayPal buttons, venmo, invoicing, payouts, or PayPal REST API. Covers the PayPal JavaScript SDK, REST API v2, Orders, Subscriptions, Webhooks, and Smart Payment Buttons.
Razorpay
Accept payments with Razorpay. Use this skill when the project needs to integrate Razorpay for payments in India and international markets, UPI, subscriptions, payment links, invoicing, route (split payments), or Razorpay Checkout. Covers the Razorpay API, Checkout.js, orders, subscriptions, webhooks, and UPI.
Square
Accept payments with Square. Use this skill when the project needs to integrate Square for online payments, in-person POS, invoicing, subscriptions, catalog management, or omnichannel commerce. Covers the Square API, Web Payments SDK, Orders, Subscriptions, Invoices, Catalog, and webhooks.