PHP code example of mrdulal / laravel-vipps
1. Go to this page and download the library: Download mrdulal/laravel-vipps library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
mrdulal / laravel-vipps example snippets
// config/app.php
'providers' => [
// ...
Mrdulal\LaravelVipps\VippsServiceProvider::class,
],
'aliases' => [
// ...
'Vipps' => Mrdulal\LaravelVipps\Facades\Vipps::class,
],
return [
// Environment (test/production)
'environment' => env('VIPPS_ENVIRONMENT', 'test'),
// API Credentials
'client_id' => env('VIPPS_CLIENT_ID'),
'client_secret' => env('VIPPS_CLIENT_SECRET'),
'subscription_key' => env('VIPPS_SUBSCRIPTION_KEY'),
'merchant_serial_number' => env('VIPPS_MERCHANT_SERIAL_NUMBER'),
// Feature toggles
'features' => [
'epayment' => true,
'checkout' => true,
'express' => true,
'recurring' => true,
'order_management' => true,
'webhooks' => true,
],
// HTTP client settings
'http' => [
'timeout' => 30,
'connect_timeout' => 10,
'verify' => true,
],
// Express checkout UI settings
'express' => [
'button_theme' => 'orange', // orange, white, white-outline
'button_size' => 'large', // small, medium, large
'show_on_cart' => true,
'show_on_product' => true,
],
];
// routes/web.php or routes/api.php
Route::post('/vipps/webhook', [\Mrdulal\LaravelVipps\Http\Controllers\WebhookController::class, 'handle']);
use Mrdulal\LaravelVipps\Facades\Vipps;
// Create a payment
$payment = Vipps::ePayment()->create([
'amount' => 10000, // Amount in øre (100.00 NOK)
'currency' => 'NOK',
'orderId' => 'order-123',
'description' => 'Payment for order #123',
'redirectUrl' => 'https://yoursite.com/payment/callback',
'userFlow' => 'WEB_REDIRECT'
]);
// Get payment details
$details = Vipps::ePayment()->getPayment($payment['orderId']);
// Capture payment
$capture = Vipps::ePayment()->capture($payment['orderId'], [
'amount' => 10000,
'description' => 'Capture for order #123'
]);
use Mrdulal\LaravelVipps\Facades\Vipps;
// Create express checkout session
$session = Vipps::express()->create([
'amount' => 10000,
'currency' => 'NOK',
'orderId' => 'order-123',
'description' => 'Express checkout for order #123',
'redirectUrl' => 'https://yoursite.com/express/callback',
'userInfo' => [
'userId' => 'user-123'
]
]);
// Generate QR code for express checkout
$qrCode = Vipps::express()->generateQrCode([
'orderId' => 'order-123',
'amount' => 10000,
'currency' => 'NOK',
'description' => 'Product purchase',
'redirectUrl' => 'https://yoursite.com/callback',
'qrFormat' => 'SVG', // or 'PNG'
'qrSize' => 300
]);
// Create shareable payment link
$shareableLink = Vipps::express()->createShareableLink([
'orderId' => 'order-456',
'amount' => 15000,
'currency' => 'NOK',
'description' => 'Shareable payment link',
'redirectUrl' => 'https://yoursite.com/callback',
'expiresAt' => now()->addHours(24)
]);
use Mrdulal\LaravelVipps\Facades\Vipps;
// Create recurring agreement
$agreement = Vipps::recurring()->createAgreement([
'currency' => 'NOK',
'price' => 9900, // 99.00 NOK
'productName' => 'Monthly Subscription',
'productDescription' => 'Premium subscription service',
'merchantRedirectUrl' => 'https://yoursite.com/recurring/callback',
'merchantAgreementUrl' => 'https://yoursite.com/agreement/123',
'interval' => 'MONTH',
'intervalCount' => 1,
'isApp' => false
]);
// Create charge for agreement
$charge = Vipps::recurring()->createCharge($agreement['agreementId'], [
'amount' => 9900,
'currency' => 'NOK',
'description' => 'Monthly subscription charge',
'orderId' => 'charge-456'
]);
// List all charges for an agreement
$charges = Vipps::recurring()->listCharges($agreement['agreementId']);
// Stop an agreement
$result = Vipps::recurring()->stopAgreement($agreement['agreementId'], [
'reason' => 'Customer requested cancellation'
]);
Vipps::ePayment()->create([
'amount' => 10000, // Required: Amount in øre (100.00 NOK)
'currency' => 'NOK', // Optional: NOK, DKK, EUR (default: NOK)
'orderId' => 'order-123', // Required: Unique order identifier
'description' => 'Payment for order #123', // Required: Payment description
'redirectUrl' => 'https://yoursite.com/callback', // Required: Callback URL
'userFlow' => 'WEB_REDIRECT', // Optional: WEB_REDIRECT, NATIVE_REDIRECT
'paymentMethod' => 'WALLET', // Optional: WALLET, CARD
'skipLandingPage' => false, // Optional: Skip Vipps landing page
'userInfo' => [ // Optional: Pre-fill user information
'userId' => 'user-123',
'mobileNumber' => '+4712345678',
'email' => '[email protected] '
],
'reference' => 'ref-456' // Optional: Your internal reference
]);
Vipps::ePayment()->capture('order-123', [
'amount' => 10000, // Required: Amount to capture
'description' => 'Capture for order #123', // Required
'reference' => 'capture-ref' // Optional
]);
Vipps::ePayment()->refund('order-123', [
'amount' => 5000, // Required: Amount to refund
'description' => 'Partial refund', // Required
'reference' => 'refund-ref' // Optional
]);
Vipps::express()->generateQrCode([
'orderId' => 'qr-order-123',
'amount' => 15000,
'currency' => 'NOK',
'description' => 'QR Code Payment',
'redirectUrl' => 'https://yoursite.com/callback',
'qrFormat' => 'SVG', // SVG or PNG
'qrSize' => 300 // Size in pixels (100-2000)
]);
Vipps::express()->createShareableLink([
'orderId' => 'share-order-123',
'amount' => 20000,
'currency' => 'NOK',
'description' => 'Shareable Payment Link',
'redirectUrl' => 'https://yoursite.com/callback',
'expiresAt' => now()->addDays(7) // Optional: Link expiration
]);
Vipps::recurring()->createAgreement([
'currency' => 'NOK',
'price' => 9900, // Monthly price in øre
'productName' => 'Premium Plan', // Max 45 characters
'productDescription' => 'Monthly premium subscription', // Max 100 chars
'merchantRedirectUrl' => 'https://yoursite.com/recurring/success',
'merchantAgreementUrl' => 'https://yoursite.com/terms',
'interval' => 'MONTH', // WEEK, MONTH, YEAR
'intervalCount' => 1, // How many intervals between charges
'isApp' => false, // True if initiated from mobile app
'phoneNumber' => '+4712345678', // Optional: Pre-fill phone
'campaign' => [ // Optional: Campaign pricing
'start' => now(),
'end' => now()->addMonths(3),
'price' => 4900 // Campaign price in øre
]
]);
$history = Vipps::orderManagement()->getPaymentHistory('order-123');
// Returns array of all transactions for the order
Vipps::orderManagement()->sendReceipt('order-123', [
'orderLines' => [
[
'name' => 'Premium Subscription',
'id' => 'sub-001',
'totalAmount' => 9900,
'totalAmountExcludingTax' => 7920,
'totalTaxAmount' => 1980,
'taxRate' => 25.0,
'unitInfo' => [
'unitPrice' => 9900,
'quantity' => '1',
'quantityUnit' => 'month'
]
]
],
'bottomLine' => [
'currency' => 'NOK',
'tipAmount' => 500,
'barcode' => [
'format' => 'EAN-13',
'data' => '1234567890123'
]
]
]);
// routes/web.php or routes/api.php
Route::post('/vipps/webhook', [\Mrdulal\LaravelVipps\Http\Controllers\WebhookController::class, 'handle']);
// app/Providers/EventServiceProvider.php
use Mrdulal\LaravelVipps\Events\{
PaymentCompleted,
PaymentCancelled,
PaymentCaptured,
PaymentRefunded,
RecurringAgreementCreated,
RecurringChargeCreated
};
protected $listen = [
PaymentCompleted::class => [
\App\Listeners\HandlePaymentCompleted::class,
],
PaymentCancelled::class => [
\App\Listeners\HandlePaymentCancelled::class,
],
PaymentCaptured::class => [
\App\Listeners\HandlePaymentCaptured::class,
],
PaymentRefunded::class => [
\App\Listeners\HandlePaymentRefunded::class,
],
RecurringAgreementCreated::class => [
\App\Listeners\HandleRecurringAgreementCreated::class,
],
RecurringChargeCreated::class => [
\App\Listeners\HandleRecurringChargeCreated::class,
],
];
namespace App\Listeners;
use Mrdulal\LaravelVipps\Events\PaymentCompleted;
use Illuminate\Contracts\Queue\ShouldQueue;
class HandlePaymentCompleted implements ShouldQueue
{
public function handle(PaymentCompleted $event): void
{
$orderId = $event->orderId;
$payload = $event->payload;
// Update your order status
$order = Order::where('order_id', $orderId)->first();
if ($order) {
$order->update(['status' => 'paid']);
// Send confirmation email
Mail::to($order->customer_email)->send(new PaymentConfirmation($order));
}
}
}
// Webhook verification is automatic, but you can customize it
'webhook' => [
'secret' => env('VIPPS_WEBHOOK_SECRET'),
'tolerance' => 300, // 5 minutes tolerance
'verify_signature' => true, // Enable signature verification
],
// Listen to all Vipps events with a single listener
Event::listen('Mrdulal\LaravelVipps\Events\*', function ($eventName, array $data) {
$eventObject = $data[0];
Log::info("Vipps event fired: {$eventName}", [
'order_id' => $eventObject->orderId,
'payload' => $eventObject->payload
]);
});
namespace Tests\Feature;
use Tests\TestCase;
use Mrdulal\LaravelVipps\Facades\Vipps;
use Mrdulal\LaravelVipps\Services\VippsClient;
use Mockery;
class VippsPaymentTest extends TestCase
{
public function test_can_create_payment()
{
// Mock the VippsClient
$mockClient = Mockery::mock(VippsClient::class);
$mockClient->shouldReceive('post')
->once()
->with('https://apitest.vipps.no/ecomm/v2/payments', Mockery::type('array'))
->andReturn([
'orderId' => 'test-order-123',
'url' => 'https://test.vipps.no/redirect-url',
'token' => 'test-token'
]);
$this->app->instance(VippsClient::class, $mockClient);
// Test payment creation
$response = Vipps::ePayment()->create([
'amount' => 10000,
'currency' => 'NOK',
'orderId' => 'test-order-123',
'description' => 'Test payment',
'redirectUrl' => 'https://example.com/callback'
]);
$this->assertEquals('test-order-123', $response['orderId']);
$this->assertArrayHasKey('url', $response);
}
}
namespace Tests\Feature;
use Tests\TestCase;
use Mrdulal\LaravelVipps\Events\PaymentCompleted;
use Illuminate\Support\Facades\Event;
class WebhookTest extends TestCase
{
public function test_payment_completed_webhook()
{
Event::fake();
$payload = [
'eventType' => 'SALE',
'transactionInfo' => [
'orderId' => 'test-order-123',
'amount' => 10000,
'status' => 'COMPLETED'
]
];
$response = $this->postJson('/vipps/webhook', $payload);
$response->assertStatus(200);
Event::assertDispatched(PaymentCompleted::class);
}
}
// phpunit.xml
<phpunit>
<php>
<env name="VIPPS_ENVIRONMENT" value="test"/>
<env name="VIPPS_CLIENT_ID" value="test_client_id"/>
<env name="VIPPS_CLIENT_SECRET" value="test_client_secret"/>
<env name="VIPPS_SUBSCRIPTION_KEY" value="test_subscription_key"/>
<env name="VIPPS_MERCHANT_SERIAL_NUMBER" value="123456"/>
</php>
</phpunit>
// config/vipps.php
return [
// Environment & Credentials
'environment' => env('VIPPS_ENVIRONMENT', 'test'),
'client_id' => env('VIPPS_CLIENT_ID'),
'client_secret' => env('VIPPS_CLIENT_SECRET'),
'subscription_key' => env('VIPPS_SUBSCRIPTION_KEY'),
'merchant_serial_number' => env('VIPPS_MERCHANT_SERIAL_NUMBER'),
// API Endpoints (auto-configured based on environment)
'api_endpoints' => [
'test' => [
'base_url' => 'https://apitest.vipps.no',
'ecom_url' => 'https://apitest.vipps.no/ecomm/v2',
'checkout_url' => 'https://apitest.vipps.no/checkout/v3',
'recurring_url' => 'https://apitest.vipps.no/recurring/v3',
'order_management_url' => 'https://apitest.vipps.no/order-management/v1',
],
'production' => [
'base_url' => 'https://api.vipps.no',
'ecom_url' => 'https://api.vipps.no/ecomm/v2',
'checkout_url' => 'https://api.vipps.no/checkout/v3',
'recurring_url' => 'https://api.vipps.no/recurring/v3',
'order_management_url' => 'https://api.vipps.no/order-management/v1',
],
],
// HTTP Client Settings
'http' => [
'timeout' => 30, // Request timeout in seconds
'connect_timeout' => 10, // Connection timeout
'verify' => true, // SSL certificate verification
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
],
// Webhook Security
'webhook' => [
'secret' => env('VIPPS_WEBHOOK_SECRET'),
'tolerance' => 300, // 5 minutes tolerance for timestamp
'verify_signature' => true, // Enable HMAC signature verification
],
// Default Payment Settings
'defaults' => [
'currency' => 'NOK',
'country' => 'NO',
'language' => 'no',
'skip_landing_page' => false,
'user_flow' => 'WEB_REDIRECT',
],
// Recurring Payment Limits
'recurring' => [
'default_interval' => 'MONTH',
'default_interval_count' => 1,
'max_amount' => 200000, // 2000.00 NOK in øre
'default_currency' => 'NOK',
],
// Express Checkout UI
'express' => [
'enabled' => true,
'button_theme' => 'orange', // orange, white, white-outline
'button_size' => 'large', // small, medium, large
'show_on_cart' => true,
'show_on_product' => true,
'show_on_category' => false,
],
// Logging & Debugging
'logging' => [
'enabled' => env('VIPPS_LOGGING_ENABLED', false),
'channel' => env('VIPPS_LOG_CHANNEL', 'default'),
'level' => env('VIPPS_LOG_LEVEL', 'info'),
'log_requests' => true, // Log API requests
'log_responses' => true, // Log API responses
'log_headers' => false, // Log headers (may contain sensitive data)
],
// Caching (for access tokens)
'cache' => [
'enabled' => true,
'ttl' => 3600, // 1 hour cache TTL
'prefix' => 'vipps_',
'store' => null, // Use default cache store
],
// Error Handling
'error_handling' => [
'retry_attempts' => 3,
'retry_delay' => 1000, // milliseconds
'throw_on_error' => true,
],
// Feature Toggles
'features' => [
'epayment' => true,
'checkout' => true,
'express' => true,
'recurring' => true,
'order_management' => true,
'webhooks' => true,
],
];
// Capture full or partial amount
$capture = Vipps::orderManagement()->capture('order-123', [
'amount' => 5000, // Partial capture (original: 10000)
'description' => 'Partial shipment - Item 1'
]);
// Multiple captures are allowed until full amount is captured
$capture2 = Vipps::orderManagement()->capture('order-123', [
'amount' => 5000, // Remaining amount
'description' => 'Final shipment - Item 2'
]);
// Refund captured payment
$refund = Vipps::orderManagement()->refund('order-123', [
'amount' => 2000, // Partial refund
'description' => 'Product return - defective item'
]);
// Cancel uncaptured payment
$cancel = Vipps::orderManagement()->cancel('order-123', [
'description' => 'Order cancelled by customer'
]);
// Get complete payment history
$history = Vipps::orderManagement()->getPaymentHistory('order-123');
// Returns: reservations, captures, refunds, cancellations
// Get current order status
$status = Vipps::orderManagement()->getOrderStatus('order-123');
VippsException // Base exception
├── VippsApiException // API-related errors
├── VippsValidationException // Input validation errors
└── Custom exceptions...
use Mrdulal\LaravelVipps\Exceptions\{VippsException, VippsValidationException, VippsApiException};
try {
$payment = Vipps::ePayment()->create($paymentData);
} catch (VippsValidationException $e) {
// Handle validation errors (400-level client errors)
$errors = $e->getValidationErrors();
foreach ($errors as $field => $messages) {
Log::warning("Validation error on {$field}: " . implode(', ', $messages));
}
return response()->json(['errors' => $errors], 422);
} catch (VippsApiException $e) {
// Handle API errors (Vipps API returned an error)
$apiError = $e->getApiError();
$statusCode = $e->getCode();
Log::error('Vipps API Error', [
'status_code' => $statusCode,
'error' => $apiError,
'message' => $e->getMessage()
]);
// Handle specific API errors
switch ($statusCode) {
case 401:
// Unauthorized - check credentials
break;
case 403:
// Forbidden - check permissions
break;
case 429:
// Rate limited - implement backoff
break;
case 500:
// Server error - retry later
break;
}
} catch (VippsException $e) {
// Handle general Vipps errors (network issues, etc.)
Log::error('Vipps General Error: ' . $e->getMessage());
} catch (\Exception $e) {
// Handle unexpected errors
Log::critical('Unexpected error in Vipps integration', [
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
// Error: Invalid credentials
[
'code' => 401,
'message' => 'Access denied',
'details' => 'Invalid client credentials'
]
// Solution: Verify your credentials in .env file
// Error: Invalid amount
[
'field' => 'amount',
'errors' => ['The amount must be at least 100 øre (1.00 NOK)']
]
// Solution: Ensure amount is in øre (multiply by 100)
$amount = 99.50 * 100; // 9950 øre
// Error: Duplicate order ID
[
'code' => 409,
'message' => 'Order ID already exists'
]
// Solution: Ensure unique order IDs
$orderId = 'order-' . time() . '-' . uniqid();
// Test basic API connectivity
try {
$client = app(VippsClient::class);
$token = $client->getAccessToken();
echo "✅ API connection successful. Token: " . substr($token, 0, 20) . "...";
} catch (Exception $e) {
echo "❌ API connection failed: " . $e->getMessage();
}
// app/Console/Commands/VippsHealthCheck.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Mrdulal\LaravelVipps\Services\VippsClient;
class VippsHealthCheck extends Command
{
protected $signature = 'vipps:health-check';
protected $description = 'Check Vipps API connectivity';
public function handle()
{
try {
$client = app(VippsClient::class);
$token = $client->getAccessToken();
$this->info('✅ Vipps API is accessible');
$this->info('Token: ' . substr($token, 0, 20) . '...');
return 0;
} catch (\Exception $e) {
$this->error('❌ Vipps API check failed: ' . $e->getMessage());
return 1;
}
}
}
// Optimize access token caching
'cache' => [
'enabled' => true,
'ttl' => 3600, // 1 hour (tokens are valid for 1 hour)
'store' => 'redis', // Use Redis for better performance
],
// Queue webhook processing for better performance
// app/Listeners/HandlePaymentCompleted.php
class HandlePaymentCompleted implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $queue = 'vipps-webhooks';
public $timeout = 60;
public $tries = 3;
public function handle(PaymentCompleted $event): void
{
// Process payment completion
}
}
// Add indexes for better query performance
Schema::table('vipps_payments', function (Blueprint $table) {
$table->index(['status', 'created_at']);
$table->index(['merchant_serial_number', 'order_id']);
});
bash
# Publish configuration file
php artisan vendor:publish --provider="Mrdulal\LaravelVipps\VippsServiceProvider" --tag="config"
# Publish migrations
php artisan vendor:publish --provider="Mrdulal\LaravelVipps\VippsServiceProvider" --tag="migrations"
# Publish views (optional)
php artisan vendor:publish --provider="Mrdulal\LaravelVipps\VippsServiceProvider" --tag="views"
bash
php artisan migrate
bash
# Cron job for health checks
# /etc/cron.d/vipps-health-check
*/5 * * * * php /path/to/artisan vipps:health-check || echo "Vipps API down" | mail -s "Alert: Vipps API Issue" [email protected]