fp/klarna-invoice
Integrate Klarna invoice payments into your Laravel app with this package, handling invoice creation and order management through a simple, framework-friendly API.
fp/klarna-invoice is a Composer-ified copy of Klarna's legacy PHP client for the Invoice API v2.x. It is not a Laravel package — think of it as a vendored SDK with a composer.json bolted on.
Minimal setup:
composer require fp/klarna-invoice
Look first at:
src/Klarna.php — the main Klarna class; everything flows through it.src/KlarnaConfig.php / src/KlarnaException.php — config container and error handling.src/pclasses.php (or KlarnaPClass) — the payment-plan objects you must fetch before invoicing.First use case — creating a basic invoice in BETA mode:
$k = new Klarna();
$k->config(
env('KLARNA_EID'),
env('KLARNA_SECRET'),
'SE', // country
'sv', // language
'SEK', // currency
Klarna::BETA // or Klarna::LIVE
);
$k->addArticle(1, 'SKU-1', 'Widget', 100.00, 25.0, 0.0, Klarna::NO_SHIPMENT);
$k->createInvoice('4400000000', Klarna::FEMALE, 'ref-1', [], true);
$invoiceNumber = $k->getInvoiceNumber();
If you are using it through Payum, install payum/klarna-invoice as well and let the KlarnaInvoiceGatewayFactory own the Klarna instance instead of constructing it yourself.
Wrap it, don't sprinkle it. Bind a single instance through a Laravel service provider and inject it. The Klarna class is stateful (it accumulates articles until createInvoice() is called), so reusing one instance across requests is a bug factory — bind it as a scoped/transient singleton, not a global.
$this->app->scoped(Klarna::class, fn () => tap(new Klarna, function ($k) {
$k->config(config('services.klarna.eid'), config('services.klarna.secret'), ...);
}));
Cache PClasses aggressively. Payment plans are per (eid, country, currency) and change on a monthly cadence. Fetch once, persist to the cache/DB, and validate against the pclass id the customer selected. Never call getPClasses() on every page load.
Address lookup pattern. For Nordic markets, run getAddresses($pno, $pclass, $country, ...) to populate the shipping form from a SSN. Always re-submit the returned address to createInvoice() — don't trust client-side echoes.
Lifecycle methods follow the reservation flow:
$k->createInvoice(...); // reserve / invoice
$k->activate($pno, $oc, ...); // post-delivery activation
$k->creditInvoice($invNo); // refunds
$k->cancelReservation($rno); // aborts
Payum integration. Use the capture action for invoice creation, status to reconcile against getInvoiceNumber(), and the KlarnaInvoice status mapper to translate Klarna's response into Payum's Payment status. Handle the webhook/callback route yourself — the SDK has no HTTP glue.
Keep amounts in minor units. Klarna's wire format is integer öre/cents. Format at the boundary; compute everything else as integers to avoid floating-point drift.
klarna/* SDKs. Treat fp/klarna-invoice as a migration constraint, not a greenfield choice.each(), create_function, and implicit null-to-string casts if you run modern PHP.--ignore-platform-reqs is your friend during install; the Composer constraints are ancient and will fight a modern PHP matrix.0x0000 / "Invalid signature" almost always means a wrong shared secret, wrong mode, or a stale timestamp (clock skew on the server). Verify NTP.getAddresses() returns a raw array; wrap it in a DTO before it escapes your service layer, because its shape is not stable across versions.KlarnaException, log the getCode()/getMessage(), and add your own idempotency around invoice creation — the SDK will happily double-create.Klarna works but breaks on upgrades; prefer decorating a thin façade class (KlarnaInvoiceService) that owns the SDK instance and is the only thing your app touches. That façade is also your migration seam when you swap to the v3 SDK.Klarna::BETA. Drive mode from config; accidentally shipping BETA credentials to production is a silent-data-loss class of bug.klarna-invoice in Payum is abandoned too. Pin it, mirror it in a private repo, or plan the migration off both at the same time.How can I help you explore Laravel packages today?