A comprehensive PHP SDK for integrating with Klarna's REST APIs. This package provides a clean, intuitive interface for all major Klarna services including Payments, Orders, Checkouts, and Customer Token management.
- Complete API Coverage: Support for Payments, Orders, Checkouts, and Customer Tokens APIs
 - Multi-Region Support: Works with EU, North America (NA), and Oceania (OC) regions
 - Environment Flexibility: Easy switching between test (playground) and live environments
 - Type-Safe: Built with proper PHP typing and comprehensive error handling
 - Developer Friendly: Intuitive method names and comprehensive documentation
 - PSR-4 Compliant: Follows PHP-FIG standards for autoloading
 - Modern PHP: Requires PHP 8.0+ with latest dependencies
 
- PHP 8.0 or higher
 - Guzzle HTTP Client 6.5+ or 7.1+
 - Carbon 2.40+ for date handling
 - Valid Klarna API credentials
 
Before using this SDK, you need to obtain API credentials from Klarna:
- For Testing: Sign up for a Klarna Playground account
 - For Production: Contact Klarna to get live API credentials
 
Klarna uses HTTP Basic Authentication with:
- Username: Your Klarna API username (UID)
 - Password: Your Klarna API password
 
The SDK automatically sets these headers:
Authorization: Basic {base64(username:password)}
Accept: application/json
Content-Type: application/json
| Region | Code | Test Base URL | Live Base URL | 
|---|---|---|---|
| Europe | EU | 
https://api.playground.klarna.com/ | 
https://api.klarna.com/ | 
| North America | NA | 
https://api-na.playground.klarna.com/ | 
https://api-na.klarna.com/ | 
| Oceania | OC | 
https://api-oc.playground.klarna.com/ | 
https://api-oc.klarna.com/ | 
Install the package via Composer:
composer require vrajroham/php-klarna<?php
use Vrajroham\PhpKlarna\PhpKlarna;
// Initialize for EU region in test mode
$klarna = new PhpKlarna(
    'your-api-username',
    'your-api-password',
    'EU',    // Region: EU, NA, or OC
    'test'   // Mode: test or live
);
// For production (live mode)
$klarna = new PhpKlarna(
    'your-live-username',
    'your-live-password',
    'EU',
    'live'
);Create a .env file:
KLARNA_USERNAME=your-api-username
KLARNA_PASSWORD=your-api-password
KLARNA_REGION=EU
KLARNA_MODE=test$klarna = new PhpKlarna(
    $_ENV['KLARNA_USERNAME'],
    $_ENV['KLARNA_PASSWORD'],
    $_ENV['KLARNA_REGION'],
    $_ENV['KLARNA_MODE']
);// 1. Create a payment session
$sessionData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 10000, // $100.00 in cents
    'order_lines' => [
        [
            'name' => 'Test Product',
            'quantity' => 1,
            'unit_price' => 10000,
            'total_amount' => 10000
        ]
    ]
];
$session = $klarna->createSession($sessionData);
echo "Session ID: " . $session->session_id;
// 2. After customer completes payment, create order
$orderData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 10000,
    'order_lines' => $sessionData['order_lines']
];
$order = $klarna->createOrderFromAuthorizationToken(
    'auth-token-from-frontend',
    $orderData
);
echo "Order ID: " . $order->order_id;The Payments API handles the core payment flow including sessions, authorizations, and order creation.
Creates a new payment session for Klarna Payments.
$sessionData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 50000, // $500.00 in cents
    'order_tax_amount' => 4167, // Tax amount in cents
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Premium Headphones',
            'quantity' => 2,
            'unit_price' => 25000,
            'tax_rate' => 1000, // 10% = 1000
            'total_amount' => 50000,
            'total_discount_amount' => 0,
            'total_tax_amount' => 4167
        ]
    ],
    'merchant_urls' => [
        'terms' => 'https://example.com/terms',
        'checkout' => 'https://example.com/checkout',
        'confirmation' => 'https://example.com/confirmation',
        'push' => 'https://example.com/push'
    ]
];
try {
    $session = $klarna->createSession($sessionData);
    echo "Session created successfully!\n";
    echo "Session ID: " . $session->session_id . "\n";
    echo "Client Token: " . $session->client_token . "\n";
} catch (Exception $e) {
    echo "Error creating session: " . $e->getMessage();
}After customer completes payment, convert the authorization to an order.
$authToken = 'klarna-auth-token-from-frontend';
$orderData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 50000,
    'order_tax_amount' => 4167,
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Premium Headphones',
            'quantity' => 2,
            'unit_price' => 25000,
            'tax_rate' => 1000,
            'total_amount' => 50000,
            'total_tax_amount' => 4167
        ]
    ],
    'merchant_reference1' => 'ORDER-12345',
    'merchant_reference2' => 'STORE-ABC'
];
try {
    $order = $klarna->createOrderFromAuthorizationToken($authToken, $orderData);
    echo "Order created successfully!\n";
    echo "Order ID: " . $order->order_id . "\n";
    echo "Klarna Reference: " . $order->klarna_reference . "\n";
} catch (Exception $e) {
    echo "Error creating order: " . $e->getMessage();
}Create a reusable customer token for future purchases.
$authToken = 'klarna-auth-token-from-frontend';
$tokenData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'billing_address' => [
        'given_name' => 'John',
        'family_name' => 'Doe',
        'email' => '[email protected]',
        'street_address' => '123 Main St',
        'postal_code' => '12345',
        'city' => 'Anytown',
        'region' => 'CA',
        'country' => 'US'
    ]
];
try {
    $customerToken = $klarna->createCustomerToken($authToken, $tokenData);
    echo "Customer token created: " . $customerToken->token_id . "\n";
} catch (Exception $e) {
    echo "Error creating customer token: " . $e->getMessage();
}Cancel an unused authorization token.
$authToken = 'klarna-auth-token-to-cancel';
try {
    $result = $klarna->cancelAuthorization($authToken, []);
    echo "Authorization cancelled successfully\n";
} catch (Exception $e) {
    echo "Error cancelling authorization: " . $e->getMessage();
}The Orders API handles post-purchase order management including captures, refunds, and order updates.
Retrieve complete order information.
$orderId = 'klarna-order-id';
try {
    $order = $klarna->order($orderId);
    echo "Order Status: " . $order->status . "\n";
    echo "Order Amount: " . $order->order_amount . "\n";
    echo "Captured Amount: " . $order->captured_amount . "\n";
    echo "Refunded Amount: " . $order->refunded_amount . "\n";
} catch (Exception $e) {
    echo "Error retrieving order: " . $e->getMessage();
}Capture all or part of an authorized order.
$orderId = 'klarna-order-id';
$captureData = [
    'captured_amount' => 25000, // $250.00 in cents
    'description' => 'Partial capture for shipped items',
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Premium Headphones',
            'quantity' => 1,
            'unit_price' => 25000,
            'total_amount' => 25000
        ]
    ]
];
try {
    $capture = $klarna->createCapture($orderId, $captureData);
    echo "Capture successful!\n";
    echo "Capture ID: " . $capture->capture_id . "\n";
} catch (Exception $e) {
    echo "Error capturing payment: " . $e->getMessage();
}Process a full or partial refund.
$orderId = 'klarna-order-id';
$refundData = [
    'refunded_amount' => 10000, // $100.00 refund
    'description' => 'Product return refund',
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Returned Item',
            'quantity' => 1,
            'unit_price' => 10000,
            'total_amount' => 10000
        ]
    ]
];
try {
    $refund = $klarna->createRefund($orderId, $refundData);
    echo "Refund processed successfully!\n";
} catch (Exception $e) {
    echo "Error processing refund: " . $e->getMessage();
}$orderId = 'klarna-order-id';
// Acknowledge order (confirm you received it)
try {
    $klarna->acknowledgeOrder($orderId);
    echo "Order acknowledged\n";
} catch (Exception $e) {
    echo "Error acknowledging order: " . $e->getMessage();
}
// Cancel order (if not captured)
try {
    $klarna->cancelOrder($orderId);
    echo "Order cancelled\n";
} catch (Exception $e) {
    echo "Error cancelling order: " . $e->getMessage();
}
// Extend authorization time (add 7 days)
try {
    $klarna->extendAuthorizationTime($orderId);
    echo "Authorization time extended\n";
} catch (Exception $e) {
    echo "Error extending authorization: " . $e->getMessage();
}
// Release remaining authorization
try {
    $klarna->releaseRemainingAuthorization($orderId);
    echo "Remaining authorization released\n";
} catch (Exception $e) {
    echo "Error releasing authorization: " . $e->getMessage();
}$orderId = 'klarna-order-id';
// Update merchant references
$merchantData = [
    'merchant_reference1' => 'NEW-ORDER-REF-123',
    'merchant_reference2' => 'UPDATED-STORE-REF'
];
try {
    $klarna->updateMerchantReferences($orderId, $merchantData);
    echo "Merchant references updated\n";
} catch (Exception $e) {
    echo "Error updating merchant references: " . $e->getMessage();
}
// Update customer details
$customerData = [
    'billing_address' => [
        'given_name' => 'John',
        'family_name' => 'Doe',
        'email' => '[email protected]',
        'street_address' => '456 New Address St',
        'postal_code' => '54321',
        'city' => 'New City',
        'region' => 'NY',
        'country' => 'US'
    ],
    'shipping_address' => [
        'given_name' => 'John',
        'family_name' => 'Doe',
        'street_address' => '456 New Address St',
        'postal_code' => '54321',
        'city' => 'New City',
        'region' => 'NY',
        'country' => 'US'
    ]
];
try {
    $klarna->updateCustomerUpdate($orderId, $customerData);
    echo "Customer details updated\n";
} catch (Exception $e) {
    echo "Error updating customer details: " . $e->getMessage();
}The Checkout API provides a complete checkout solution with Klarna's hosted checkout.
Create a new checkout session with a complete shopping experience.
$checkoutData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 75000, // $750.00
    'order_tax_amount' => 6250,
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Wireless Mouse',
            'quantity' => 3,
            'unit_price' => 25000,
            'tax_rate' => 1000,
            'total_amount' => 75000,
            'total_tax_amount' => 6250
        ]
    ],
    'merchant_urls' => [
        'terms' => 'https://example.com/terms',
        'checkout' => 'https://example.com/checkout?order_id={checkout.order.id}',
        'confirmation' => 'https://example.com/confirmation?order_id={checkout.order.id}',
        'push' => 'https://example.com/push?order_id={checkout.order.id}'
    ],
    'options' => [
        'allow_separate_shipping_address' => true,
        'date_of_birth_mandatory' => false,
        'require_validate_callback_success' => true
    ],
    'external_payment_methods' => [
        [
            'name' => 'PayPal',
            'redirect_url' => 'https://example.com/paypal',
            'image_url' => 'https://example.com/paypal-logo.png'
        ]
    ]
];
try {
    $checkout = $klarna->createCheckoutOrder($checkoutData);
    echo "Checkout created successfully!\n";
    echo "Order ID: " . $checkout->order_id . "\n";
    echo "HTML Snippet: " . $checkout->html_snippet . "\n";
} catch (Exception $e) {
    echo "Error creating checkout: " . $e->getMessage();
}Get the current state of a checkout order.
$checkoutOrderId = 'checkout-order-id';
try {
    $checkout = $klarna->getCheckoutOrder($checkoutOrderId);
    echo "Checkout Status: " . $checkout->status . "\n";
    echo "Order Amount: " . $checkout->order_amount . "\n";
    
    if ($checkout->status === 'checkout_complete') {
        echo "Klarna Reference: " . $checkout->klarna_reference . "\n";
    }
} catch (Exception $e) {
    echo "Error retrieving checkout: " . $e->getMessage();
}Modify an existing checkout order (only possible before completion).
$checkoutOrderId = 'checkout-order-id';
$updateData = [
    'order_amount' => 85000, // Updated amount
    'order_tax_amount' => 7083,
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Wireless Mouse',
            'quantity' => 3,
            'unit_price' => 25000,
            'tax_rate' => 1000,
            'total_amount' => 75000,
            'total_tax_amount' => 6250
        ],
        [
            'type' => 'shipping_fee',
            'name' => 'Express Shipping',
            'quantity' => 1,
            'unit_price' => 10000,
            'tax_rate' => 1000,
            'total_amount' => 10000,
            'total_tax_amount' => 833
        ]
    ]
];
try {
    $updated = $klarna->updateCheckoutOrder($checkoutOrderId, $updateData);
    echo "Checkout updated successfully!\n";
} catch (Exception $e) {
    echo "Error updating checkout: " . $e->getMessage();
}Manage stored customer payment methods for recurring purchases.
Retrieve details about a stored customer token.
$tokenId = 'customer-token-id';
try {
    $token = $klarna->customerToken($tokenId);
    echo "Token Status: " . $token->status . "\n";
    echo "Payment Method: " . $token->payment_method_type . "\n";
    echo "Masked Number: " . $token->masked_number . "\n";
} catch (Exception $e) {
    echo "Error retrieving customer token: " . $e->getMessage();
}Use a stored customer token to create a new order.
$tokenId = 'customer-token-id';
$orderData = [
    'purchase_country' => 'US',
    'purchase_currency' => 'USD',
    'locale' => 'en-US',
    'order_amount' => 35000,
    'order_tax_amount' => 2917,
    'order_lines' => [
        [
            'type' => 'physical',
            'name' => 'Monthly Subscription Box',
            'quantity' => 1,
            'unit_price' => 35000,
            'tax_rate' => 1000,
            'total_amount' => 35000,
            'total_tax_amount' => 2917
        ]
    ],
    'merchant_reference1' => 'SUBSCRIPTION-789',
    'auto_capture' => true
];
try {
    $order = $klarna->createOrderFromCustomerToken($tokenId, $orderData);
    echo "Recurring order created!\n";
    echo "Order ID: " . $order->order_id . "\n";
    echo "Fraud Status: " . $order->fraud_status . "\n";
} catch (Exception $e) {
    echo "Error creating order from token: " . $e->getMessage();
}Customize the Guzzle HTTP client for specific needs:
use GuzzleHttp\Client;
$klarna = new PhpKlarna('username', 'password', 'EU', 'test');
// Create custom client with additional options
$customClient = new Client([
    'base_uri' => $klarna->getBaseUri('EU', 'test'),
    'timeout' => 30,
    'verify' => true, // Enable SSL verification
    'headers' => [
        'Authorization' => 'Basic ' . base64_encode('username:password'),
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
        'User-Agent' => 'MyApp/1.0'
    ]
]);
$klarna->setClient($customClient);The SDK provides specific exceptions for different error scenarios:
use Vrajroham\PhpKlarna\Exceptions\ValidationException;
use Vrajroham\PhpKlarna\Exceptions\NotFoundException;
use Vrajroham\PhpKlarna\Exceptions\FailedActionException;
try {
    $order = $klarna->order('invalid-order-id');
} catch (ValidationException $e) {
    // Handle validation errors (HTTP 422)
    echo "Validation Error: " . json_encode($e->getErrors());
} catch (NotFoundException $e) {
    // Handle not found errors (HTTP 404)
    echo "Resource not found";
} catch (FailedActionException $e) {
    // Handle other API errors (HTTP 400)
    echo "API Error: " . $e->getMessage();
} catch (Exception $e) {
    // Handle any other errors
    echo "Unexpected Error: " . $e->getMessage();
}The SDK includes utilities for working with Klarna's date formats:
// Convert date to Klarna format
$klarnaDate = $klarna->convertDateFormat('2023-12-25 15:30:00', 'Y-m-d\TH:i:s\Z');
echo $klarnaDate; // 2023-12-25T15:30:00Z
// Default format (YmdHis)
$defaultFormat = $klarna->convertDateFormat('2023-12-25 15:30:00');
echo $defaultFormat; // 20231225153000While not directly part of this SDK, here's how to validate Klarna webhooks:
function validateKlarnaWebhook($payload, $signature, $secret) {
    $calculatedSignature = base64_encode(
        hash_hmac('sha256', $payload, $secret, true)
    );
    
    return hash_equals($signature, $calculatedSignature);
}
// In your webhook endpoint
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_KLARNA_HMAC_SHA256'] ?? '';
if (validateKlarnaWebhook($payload, $signature, 'your-webhook-secret')) {
    $data = json_decode($payload, true);
    // Process webhook data
} else {
    http_response_code(401);
    exit('Invalid signature');
}- Environment Management: Always use environment variables for credentials
 - Error Handling: Implement comprehensive error handling for all API calls
 - Logging: Log API responses for debugging and audit trails
 - Idempotency: Use unique merchant references to prevent duplicate orders
 - Security: Never store API credentials in version control
 - Testing: Always test thoroughly in playground environment before going live
 
// Example with comprehensive error handling and logging
function createKlarnaOrder($authToken, $orderData, $logger = null) {
    try {
        $klarna = new PhpKlarna(
            $_ENV['KLARNA_USERNAME'],
            $_ENV['KLARNA_PASSWORD'],
            $_ENV['KLARNA_REGION'],
            $_ENV['KLARNA_MODE']
        );
        
        $order = $klarna->createOrderFromAuthorizationToken($authToken, $orderData);
        
        if ($logger) {
            $logger->info('Klarna order created', [
                'order_id' => $order->order_id,
                'klarna_reference' => $order->klarna_reference,
                'amount' => $orderData['order_amount']
            ]);
        }
        
        return $order;
        
    } catch (ValidationException $e) {
        if ($logger) {
            $logger->error('Klarna validation error', ['errors' => $e->getErrors()]);
        }
        throw new Exception('Invalid order data provided');
        
    } catch (Exception $e) {
        if ($logger) {
            $logger->error('Klarna API error', ['message' => $e->getMessage()]);
        }
        throw new Exception('Payment processing failed');
    }
}Run the test suite:
composer testRun tests with coverage:
composer test-coverage- Use Playground Environment: Always test with Klarna's playground environment first
 - Test Error Scenarios: Verify your error handling works correctly
 - Validate Webhooks: Test webhook validation and processing
 - Test All Flows: Test complete payment flows from session to capture/refund
 
Example test with PHPUnit:
class KlarnaIntegrationTest extends TestCase
{
    private $klarna;
    
    protected function setUp(): void
    {
        $this->klarna = new PhpKlarna(
            'test-username',
            'test-password',
            'EU',
            'test'
        );
    }
    
    public function testCreateSession()
    {
        $sessionData = [
            'purchase_country' => 'US',
            'purchase_currency' => 'USD',
            'locale' => 'en-US',
            'order_amount' => 10000,
            'order_lines' => [
                [
                    'name' => 'Test Product',
                    'quantity' => 1,
                    'unit_price' => 10000,
                    'total_amount' => 10000
                ]
            ]
        ];
        
        $session = $this->klarna->createSession($sessionData);
        
        $this->assertNotNull($session->session_id);
        $this->assertNotNull($session->client_token);
    }
}Problem: Getting 401 Unauthorized errors Solution:
- Verify your username and password are correct
 - Check that you're using the right region (EU/NA/OC)
 - Ensure you're using test credentials with playground URLs
 
Problem: ValidationException about invalid region
Solution: Use uppercase region codes: 'EU', 'NA', or 'OC'
Problem: SSL verification failures in development Solution:
// Only for development - never in production
$customClient = new Client([
    'verify' => false // Disable SSL verification
]);
$klarna->setClient($customClient);Problem: NotFoundException when accessing orders
Solution:
- Verify the order ID is correct
 - Check that the order was created in the same environment (test/live)
 - Ensure sufficient time has passed for order creation to complete
 
Q: Can I use this package with Laravel?
A: Yes! This package works perfectly with Laravel. Add credentials to your .env file and use dependency injection.
Q: How do I handle webhooks? A: Klarna sends webhooks for order events. Implement webhook validation using HMAC-SHA256 as shown in the advanced usage section.
Q: What's the difference between Payments and Checkout APIs? A: Payments API gives you more control over the UI, while Checkout API provides Klarna's hosted checkout experience.
Q: Can I test without real money? A: Yes! Use the playground environment with test credentials. No real money is processed.
Q: How do I go from test to production? A: Change the mode from 'test' to 'live' and use your production credentials from Klarna.
Q: What currencies are supported? A: Klarna supports many currencies. Check Klarna's documentation for the complete list.
Q: How do I handle different regions? A: Set the appropriate region (EU/NA/OC) when initializing the client based on your merchant account.
- Documentation: Klarna Developers
 - Issues: GitHub Issues
 - Email: [email protected]
 
Please see CHANGELOG for more information about recent changes.
Please see CONTRIBUTING for details on how to contribute.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
Built with β€οΈ for the PHP community