Klarna is a buy now, pay later (BNPL) payment method that offers flexible payment options and supports recurring payments through merchant-initiated transactions (MIT).
Setup
A Klarna account can be requested from the
Klarna Business Portal .
Credentials
To connect a Klarna account, obtain the following credentials from the Klarna Business Portal.
Username: An API username which can be generated by navigating to Preferences → Settings → Manage Klarna API Credentials
Password: An API password which can be generated by navigating to Preferences → Settings → Manage Klarna API Credentials
Region: The region of the Klarna account. Enter EU for Europe, NA for North America, or OC for Oceania
Features
Klarna supports the following features:
Delayed capture - Authorize a payment and capture it at a later time
Partial capture - Capture a portion of the authorized amount
Partial refunds - Refund a portion of the captured amount
Refunds - Refund transactions in full
Void - Cancel an authorized transaction before capture
Payment method tokenization - Store Klarna payment methods for future recurring use
Supported countries
Klarna supports transactions from buyers in the following countries:
Country code Country code Country code Country code Country code Country code Country code Country code ATAUBECACHDEDKESFIFRGBIEITNLNOPLPTSEUS
Supported currencies
Klarna supports processing payments in the following currencies:
Currency code Currency code Currency code Currency code Currency code Currency code Currency code Currency code AUDCADCHFDKKEURGBPNOKPLNSEKUSD
Limitations
The following features are not supported by this connector:
Direct capture - Immediate settlement is not supported; authorization must be captured separately
Multi-capture - Multiple captures against a single authorization are not supported
Over capture - Capturing more than the authorized amount is not supported
Incremental authorization - Increasing the authorized amount is not supported
Partial authorization - Accepting a partial amount when the full amount cannot be authorized is not supported
Zero auth - Zero-dollar verification transactions are not supported
Network tokens - Network tokenization is not supported
3-D Secure - 3DS authentication is not applicable
Transaction sync - Automatic transaction status synchronization is not supported
Settlement reporting - Automatic settlement reporting is not supported
Integration
For Klarna, the default integration uses a redirect to the Klarna hosted payments page. A direct integration using the Klarna JavaScript SDK or mobile SDKs is also supported.
Redirect integration
Start by creating a new transaction with the following required fields.
C#
Go
Java
PHP
Python
TypeScript
var transaction = await client . Transactions . CreateAsync (
transactionCreate : new TransactionCreate ()
{
Amount = 1299 ,
Currency = "USD" ,
Country = "US" ,
PaymentMethod = new PaymentMethodRequest ()
{
Method = "klarna" ,
RedirectUrl = "https://example.com/callback" ,
Country = "US" ,
Currency = "USD" ,
},
}
);
amount := int64 ( 1299 )
currency := "USD"
country := "US"
transactionCreate := components . TransactionCreate {
Amount : & amount ,
Currency : currency ,
Country : & country ,
PaymentMethod : & components . PaymentMethodRequest {
Method : "klarna" ,
RedirectUrl : "https://example.com/callback" ,
Country : "US" ,
Currency : "USD" ,
},
}
transaction , err := client . Transactions . Create ( ctx , transactionCreate , nil , nil )
CreateTransactionResponse transactionResponse = gr4vyClient . transactions (). create ()
. transactionCreate ( TransactionCreate . builder ()
. amount ( 1299L )
. currency ( "USD" )
. country ( "US" )
. paymentMethod ( new PaymentMethodRequest. Builder ()
. method ( "klarna" )
. redirectUrl ( "https://example.com/callback" )
. country ( "US" )
. currency ( "USD" )
. build ())
. build ())
. call ();
Transaction transaction = transactionResponse . transaction (). orElse ( null );
$transactionCreate = new TransactionCreate (
amount : 1299 ,
currency : 'USD' ,
country : 'US' ,
paymentMethod : new PaymentMethodRequest (
method : 'klarna' ,
redirectUrl : 'https://example.com/callback' ,
country : 'US' ,
currency : 'USD' ,
)
);
$response = $client -> transactions -> create ( $transactionCreate );
$transaction = $response -> transaction ;
transaction: models.Transaction = client.transactions.create(
amount = 1299 ,
currency = "USD" ,
country = "US" ,
payment_method = {
"method" : "klarna" ,
"redirect_url" : "https://example.com/callback" ,
"country" : "US" ,
"currency" : "USD" ,
}
)
const transaction = await gr4vy . transactions . create ({
amount: 1299 ,
currency: "USD" ,
country: "US" ,
paymentMethod: {
method: "klarna" ,
redirectUrl: "https://example.com/callback" ,
country: "US" ,
currency: "USD" ,
},
});
After the transaction is created, the API response includes payment_method.approval_url and the buyer_approval_pending status.
{
"type" : "transaction" ,
"id" : "ea1efdd0-20f9-44d9-9b0b-0a3d71e9b625" ,
"payment_method" : {
"type" : "payment-method" ,
"approval_url" : "https://cdn.sandbox.spider.gr4vy.app/connectors/klarna/apm.html?token=..."
},
"method" : "klarna"
}
Redirect the buyer to the approval_url to complete the Klarna approval flow. Once approved, the transaction moves to authorization_succeeded.
Direct integration
Gr4vy supports direct integration with Klarna using the Klarna Payments SDK or mobile SDKs, allowing you to embed the payment UI directly in your app while using Gr4vy to manage the transaction lifecycle.
To initiate a direct integration, create a transaction with integration_client set to web, ios, or android. For mobile, use your app deep link for redirect_url (for example, yourapp://).
After the transaction is created, the API response includes a session_token which can be used to get the session data for that transaction.
POST /transactions/:transaction_id/session?token=:session_token
{
"session_data" : {
"client_token" : "..." ,
"purchase_country" : "US" ,
"purchase_currency" : "USD" ,
"amount" : 1000
},
"default_completion_url" : "https://api.sandbox.spider.gr4vy.app/transactions/approve/some-token" ,
"integration_client" : "web"
}
{
"session_data" : {
"client_token" : "..." ,
"purchase_country" : "US" ,
"purchase_currency" : "USD" ,
"amount" : 1000
},
"default_completion_url" : "https://api.sandbox.spider.gr4vy.app/transactions/approve/some-token" ,
"integration_client" : "ios"
}
{
"session_data" : {
"client_token" : "..." ,
"purchase_country" : "US" ,
"purchase_currency" : "USD" ,
"amount" : 1000
},
"default_completion_url" : "https://api.sandbox.spider.gr4vy.app/transactions/approve/some-token" ,
"integration_client" : "android"
}
Use the client_token from the session data to initialize the Klarna SDK. Refer to the Klarna SDK documentation for web, iOS, and Android integration guides.
Complete the transaction
After the customer authorizes the payment through the Klarna SDK, Klarna returns an authorization_token. To finalize the transaction, send this token to Gr4vy as a query parameter on the default_completion_url returned in the session response.
curl -X GET \
"<default_completion_url>?authorization_token=<AUTHORIZATION_TOKEN>"
Once the request completes successfully, the transaction moves to authorization_succeeded. It can then be captured, voided, or refunded through Gr4vy.
Subscriptions (MIT)
Klarna supports storing the buyer’s payment method during the first (customer-present) payment and charging future renewals as merchant-initiated transactions (MIT) using the saved payment method, typically with no redirect.
Webhooks must be configured for the Klarna payment service. After the buyer approves the payment, Klarna sends an authorization_token via webhook which Gr4vy uses to create the reusable customer token. Without this webhook, store: true will not work.
First payment
Set store to true to save the Klarna payment method for the buyer.
C#
Go
Java
PHP
Python
TypeScript
using Gr4vy ;
using Gr4vy . Models . Components ;
// Load your private key from disk, env, or your secret manager
var privateKey = "..." ;
var sdk = new Gr4vySDK (
id : "example" ,
server : SDKConfig . Server . Sandbox ,
bearerAuthSource : Auth . WithToken ( privateKey ),
merchantAccountId : "default"
);
var res = await sdk . Transactions . CreateAsync ( transactionCreate : new TransactionCreate () {
Amount = 5000 ,
Currency = "USD" ,
Country = "US" ,
PaymentMethod = new PaymentMethodRequest () {
Method = "klarna" ,
RedirectUrl = "https://yourapp.com/callback" ,
Country = "US" ,
Currency = "USD"
},
Store = true ,
PaymentSource = "recurring" ,
MerchantInitiated = false ,
IsSubsequentPayment = false ,
});
// handle response
package main
import (
"context"
"log"
"github.com/gr4vy/gr4vy-go"
"github.com/gr4vy/gr4vy-go/models/components"
)
func main () {
// Load your private key from disk, env, or your secret manager
privateKey := "..."
s := gr4vy . New (
gr4vy . WithID ( "example" ),
gr4vy . WithServer ( gr4vy . ServerSandbox ),
gr4vy . WithBearerAuth ( gr4vy . WithToken ( privateKey )),
gr4vy . WithMerchantAccountID ( "default" ),
)
amount := int64 ( 5000 )
store := true
merchantInitiated := false
isSubsequentPayment := false
res , err := s . Transactions . Create ( context . Background (), & components . TransactionCreate {
Amount : & amount ,
Currency : "USD" ,
Country : "US" ,
PaymentMethod : & components . PaymentMethodRequest {
Method : "klarna" ,
RedirectUrl : "https://yourapp.com/callback" ,
Country : "US" ,
Currency : "USD" ,
},
Store : & store ,
PaymentSource : "recurring" ,
MerchantInitiated : & merchantInitiated ,
IsSubsequentPayment : & isSubsequentPayment ,
})
if err != nil {
log . Fatal ( err )
}
if res . StatusCode == 201 {
// handle response
}
}
import com.gr4vy.Gr4vy;
import com.gr4vy.models.components. * ;
import com.gr4vy.models.operations. * ;
public class Main {
public static void main ( String [] args ) {
// Load your private key from disk, env, or your secret manager
String privateKey = "..." ;
Gr4vy sdk = new Gr4vy. Builder ()
. id ( "example" )
. server ( Server . SANDBOX )
. bearerAuth ( Auth . withToken (privateKey))
. merchantAccountId ( "default" )
. build ();
TransactionCreate transactionCreate = new TransactionCreate. Builder ()
. amount ( 5000 )
. currency ( "USD" )
. country ( "US" )
. paymentMethod ( new PaymentMethodRequest. Builder ()
. method ( "klarna" )
. redirectUrl ( "https://yourapp.com/callback" )
. country ( "US" )
. currency ( "USD" )
. build ())
. store ( true )
. paymentSource ( "recurring" )
. merchantInitiated ( false )
. isSubsequentPayment ( false )
. build ();
try {
CreateTransactionResponse res = sdk . transactions (). create (transactionCreate);
if ( res . statusCode == 201 ) {
// handle response
}
} catch ( Exception e ) {
// handle exception
}
}
}
<? php
require_once 'vendor/autoload.php' ;
use Gr4vy ;
use Gr4vy\ Auth ;
use Gr4vy\Models\ Components ;
// Load your private key from disk, env, or your secret manager
$privateKey = '...' ;
$sdk = Gr4vy\ SDK :: builder ()
-> setId ( 'example' )
-> setServer ( 'sandbox' )
-> setSecuritySource ( Auth :: withToken ( $privateKey ))
-> setMerchantAccountId ( 'default' )
-> build ();
$res = $sdk -> transactions -> create ( new Components\ TransactionCreate (
amount : 5000 ,
currency : 'USD' ,
country : 'US' ,
paymentMethod : new Components\ PaymentMethodRequest (
method : 'klarna' ,
redirectUrl : 'https://yourapp.com/callback' ,
country : 'US' ,
currency : 'USD' ,
),
store : true ,
paymentSource : 'recurring' ,
merchantInitiated : false ,
isSubsequentPayment : false ,
));
if ( $res -> statusCode === 201 ) {
// handle response
}
import gr4vy
from gr4vy import auth
from gr4vy.models import components
# Load your private key from disk, env, or your secret manager
private_key = "..."
s = gr4vy.Gr4vy(
id = "example" ,
server = gr4vy. SERVER_SANDBOX ,
bearer_auth = auth.with_token(private_key),
merchant_account_id = "default" ,
)
res = s.transactions.create(
components.TransactionCreate(
amount = 5000 ,
currency = "USD" ,
country = "US" ,
payment_method = components.PaymentMethodRequest(
method = "klarna" ,
redirect_url = "https://yourapp.com/callback" ,
country = "US" ,
currency = "USD" ,
),
store = True ,
payment_source = "recurring" ,
merchant_initiated = False ,
is_subsequent_payment = False ,
),
)
if res.status_code == 201 :
# handle response
pass
import { Gr4vy , withToken } from "@gr4vy/sdk" ;
// Load your private key from disk, env, or your secret manager
const privateKey = process . env . GR4VY_PRIVATE_KEY ?? "..." ;
const gr4vy = new Gr4vy ({
id: "example" ,
server: "sandbox" ,
bearerAuth: withToken ({ privateKey }),
merchantAccountId: "default" ,
});
const res = await gr4vy . transactions . create ({
amount: 5000 ,
currency: "USD" ,
country: "US" ,
paymentMethod: {
method: "klarna" ,
redirectUrl: "https://yourapp.com/callback" ,
country: "US" ,
currency: "USD" ,
},
store: true ,
paymentSource: "recurring" ,
merchantInitiated: false ,
isSubsequentPayment: false ,
});
if ( res . statusCode === 201 ) {
// handle response
}
Subsequent payment
After the payment method is saved, use the payment method ID to charge future renewals.
Set payment_method.method to id and pass the saved payment method ID.
Set payment_source to recurring.
Set merchant_initiated and is_subsequent_payment to true.
C#
Go
Java
PHP
Python
TypeScript
using Gr4vy ;
using Gr4vy . Models . Components ;
// Load your private key from disk, env, or your secret manager
var privateKey = "..." ;
var sdk = new Gr4vySDK (
id : "example" ,
server : SDKConfig . Server . Sandbox ,
bearerAuthSource : Auth . WithToken ( privateKey ),
merchantAccountId : "default"
);
var res = await sdk . Transactions . CreateAsync ( transactionCreate : new TransactionCreate () {
Amount = 5000 ,
Currency = "USD" ,
Country = "US" ,
PaymentMethod = new PaymentMethodRequest () {
Method = "id" ,
Id = "c2495b14-ca95-4199-87c3-27cbfefcbe9e"
},
PaymentSource = "recurring" ,
MerchantInitiated = true ,
IsSubsequentPayment = true ,
});
// handle response
package main
import (
"context"
"log"
"github.com/gr4vy/gr4vy-go"
"github.com/gr4vy/gr4vy-go/models/components"
)
func main () {
// Load your private key from disk, env, or your secret manager
privateKey := "..."
s := gr4vy . New (
gr4vy . WithID ( "example" ),
gr4vy . WithServer ( gr4vy . ServerSandbox ),
gr4vy . WithBearerAuth ( gr4vy . WithToken ( privateKey )),
gr4vy . WithMerchantAccountID ( "default" ),
)
amount := int64 ( 5000 )
merchantInitiated := true
isSubsequentPayment := true
res , err := s . Transactions . Create ( context . Background (), & components . TransactionCreate {
Amount : & amount ,
Currency : "USD" ,
Country : "US" ,
PaymentMethod : & components . PaymentMethodRequest {
Method : "id" ,
Id : "c2495b14-ca95-4199-87c3-27cbfefcbe9e" ,
},
PaymentSource : "recurring" ,
MerchantInitiated : & merchantInitiated ,
IsSubsequentPayment : & isSubsequentPayment ,
})
if err != nil {
log . Fatal ( err )
}
if res . StatusCode == 201 {
// handle response
}
}
import com.gr4vy.Gr4vy;
import com.gr4vy.models.components. * ;
import com.gr4vy.models.operations. * ;
public class Main {
public static void main ( String [] args ) {
// Load your private key from disk, env, or your secret manager
String privateKey = "..." ;
Gr4vy sdk = new Gr4vy. Builder ()
. id ( "example" )
. server ( Server . SANDBOX )
. bearerAuth ( Auth . withToken (privateKey))
. merchantAccountId ( "default" )
. build ();
TransactionCreate transactionCreate = new TransactionCreate. Builder ()
. amount ( 5000 )
. currency ( "USD" )
. country ( "US" )
. paymentMethod ( new PaymentMethodRequest. Builder ()
. method ( "id" )
. id ( "c2495b14-ca95-4199-87c3-27cbfefcbe9e" )
. build ())
. paymentSource ( "recurring" )
. merchantInitiated ( true )
. isSubsequentPayment ( true )
. build ();
try {
CreateTransactionResponse res = sdk . transactions (). create (transactionCreate);
if ( res . statusCode == 201 ) {
// handle response
}
} catch ( Exception e ) {
// handle exception
}
}
}
<? php
require_once 'vendor/autoload.php' ;
use Gr4vy ;
use Gr4vy\ Auth ;
use Gr4vy\Models\ Components ;
// Load your private key from disk, env, or your secret manager
$privateKey = '...' ;
$sdk = Gr4vy\ SDK :: builder ()
-> setId ( 'example' )
-> setServer ( 'sandbox' )
-> setSecuritySource ( Auth :: withToken ( $privateKey ))
-> setMerchantAccountId ( 'default' )
-> build ();
$res = $sdk -> transactions -> create ( new Components\ TransactionCreate (
amount : 5000 ,
currency : 'USD' ,
country : 'US' ,
paymentMethod : new Components\ PaymentMethodRequest (
method : 'id' ,
id : 'c2495b14-ca95-4199-87c3-27cbfefcbe9e' ,
),
paymentSource : 'recurring' ,
merchantInitiated : true ,
isSubsequentPayment : true ,
));
if ( $res -> statusCode === 201 ) {
// handle response
}
import gr4vy
from gr4vy import auth
from gr4vy.models import components
# Load your private key from disk, env, or your secret manager
private_key = "..."
s = gr4vy.Gr4vy(
id = "example" ,
server = gr4vy. SERVER_SANDBOX ,
bearer_auth = auth.with_token(private_key),
merchant_account_id = "default" ,
)
res = s.transactions.create(
components.TransactionCreate(
amount = 5000 ,
currency = "USD" ,
country = "US" ,
payment_method = components.PaymentMethodRequest(
method = "id" ,
id = "c2495b14-ca95-4199-87c3-27cbfefcbe9e" ,
),
payment_source = "recurring" ,
merchant_initiated = True ,
is_subsequent_payment = True ,
),
)
if res.status_code == 201 :
# handle response
pass
import { Gr4vy , withToken } from "@gr4vy/sdk" ;
// Load your private key from disk, env, or your secret manager
const privateKey = process . env . GR4VY_PRIVATE_KEY ?? "..." ;
const gr4vy = new Gr4vy ({
id: "example" ,
server: "sandbox" ,
bearerAuth: withToken ({ privateKey }),
merchantAccountId: "default" ,
});
const res = await gr4vy . transactions . create ({
amount: 5000 ,
currency: "USD" ,
country: "US" ,
paymentMethod: {
method: "id" ,
id: "c2495b14-ca95-4199-87c3-27cbfefcbe9e" ,
},
paymentSource: "recurring" ,
merchantInitiated: true ,
isSubsequentPayment: true ,
});
if ( res . statusCode === 201 ) {
// handle response
}