nordkit/svea
Modern PHP SDK for Svea Checkout, Payment Admin, webhook subscriptions and inbound webhook verification. Fluent API with typed value objects, retries, idempotency, async task polling, and a robust testing fake. Includes first-class Laravel integration.
Installation:
composer require nordkit/svea
For Laravel, publish the config:
php artisan vendor:publish --tag=svea-config
Configure .env:
SVEA_MERCHANT_ID=your_merchant_id
SVEA_SHARED_SECRET=your_shared_secret
SVEA_ENVIRONMENT=test
SVEA_WEBHOOK_SECRET=your_webhook_secret
First Use Case: Create a checkout order in a Laravel controller:
use Svea\Laravel\Svea;
public function createCheckout()
{
$order = Svea::checkout()->create(new CheckoutOrder(
currency: 'SEK',
countryCode: 'SE',
locale: 'sv-SE',
clientOrderNumber: 'ORD-001',
merchantSettings: new MerchantSettings(
pushUri: route('webhooks.svea'),
termsUri: route('terms'),
confirmationUri: route('checkout.confirmation'),
checkoutUri: route('checkout'),
),
cart: new Cart([new OrderRow(quantity: 100, unitPrice: 29900, vatPercent: 2500, sku: 'TSHIRT-BLK-M', name: 'T-Shirt Black M')])
));
return response()->json(['snippet' => $order->snippet()]);
}
Checkout Flow:
// Create order
$order = Svea::checkout()->create(...);
// Embed snippet in view
return view('checkout', ['snippet' => $order->snippet()]);
// Handle webhook (Laravel)
public function handleWebhook(Request $request)
{
$event = Svea::webhook()->verify($request);
// Process event
}
Admin Operations:
Svea::admin()->order('12345678')->deliver();
Svea::admin()->order('12345678')->cancel();
Subscriptions:
Svea::subscriptions()->add(
callbackUrl: route('webhooks.svea.subscription'),
events: ['CheckoutOrder.Created', 'CheckoutOrder.Delivered']
);
Svea::checkout(), Svea::admin(), or Svea::subscriptions() for concise syntax.Svea::admin()->order('12345678')
->withIdempotencyKey('unique-key')
->deliver();
Svea::webhook()->verify($request) in your webhook endpoint.Svea::fake() for isolated tests:
Svea::fake()->assertCheckoutWasCreated(function (CheckoutOrder $order) {
$order->currency('SEK');
});
Minor-Unit Convention:
29900 for 299.00 SEK instead of 299) causes API failures.Svea\Money::minor(299) or Svea\Money::percent(25) for vatPercent.Webhook Signature Mismatch:
SVEA_WEBHOOK_SECRET in .env throws SignatureVerificationException.Idempotency Keys:
deliver()) may cause duplicate payments.Async Task Polling:
Svea::admin()->task('task-id')->poll() to check status.$this->app->singleton(SveaClient::class, fn () => new SveaClient(
config: config('svea'),
handlerStack: HandlerStack::create()->push(WiretapMiddleware::make(app(Wiretap::class)))
));
SveaApiException provides detailed error info (status code, body). Log or display:
try {
Svea::admin()->order('12345678')->deliver();
} catch (SveaApiException $e) {
Log::error('Svea error: ' . $e->getMessage());
}
Conditional Logic:
Use when() for branching logic:
Svea::admin()->order('12345678')
->when($isPartial, fn ($req) => $req->deliver(rows: $rowIds))
->unless($isCancelled, fn ($req) => $req->cancel());
Retry Configuration: Enable retries for transient failures:
Svea::admin()->withRetries(3)->order('12345678')->deliver();
Testing:
Svea::fake() to mock responses:
Svea::fake()->checkout()->shouldCreate(fn () => new CheckoutOrderResponse('12345678'));
Svea::fake()->assertCheckoutWasCreated();
Environment Overrides: Point to local mock servers during development:
SVEA_CHECKOUT_URL=http://localhost:8000/checkout
SVEA_ADMIN_URL=http://localhost:8000/admin
Subscription Management:
php artisan svea:subscription:add --events=CheckoutOrder.Created
php artisan svea:subscription:verify {id}
How can I help you explore Laravel packages today?