PHPackages                             coretrekas/vipps - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. coretrekas/vipps

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

coretrekas/vipps
================

PHP SDK for Vipps MobilePay APIs

v1.2.2(5mo ago)1893↓90%MITPHPPHP ^8.1CI passing

Since Oct 15Pushed 5mo agoCompare

[ Source](https://github.com/coretrekas/vipps)[ Packagist](https://packagist.org/packages/coretrekas/vipps)[ RSS](/packages/coretrekas-vipps/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (9)Versions (8)Used By (0)

Vipps MobilePay PHP SDK
=======================

[](#vipps-mobilepay-php-sdk)

[![Latest Version](https://camo.githubusercontent.com/4dc735eb65201d269eb247ad8057f107227367cbd50f1914d9410b6e780c5dc4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636f72657472656b61732f76697070732e737667)](https://packagist.org/packages/coretrekas/vipps)[![PHP Version](https://camo.githubusercontent.com/77f1285b6140222af92fbd19b7bed6a358671d44decab30920a1a753c410d213/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f636f72657472656b61732f76697070732e737667)](https://packagist.org/packages/coretrekas/vipps)[![License](https://camo.githubusercontent.com/2e089517ff3586ae329e76b73dab25aac7289f944fc2d83a7a52e86a5ee5da7c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f636f72657472656b61732f76697070732e737667)](https://packagist.org/packages/coretrekas/vipps)

A comprehensive, production-ready PHP SDK for Vipps MobilePay APIs, providing easy integration with:

- **ePayment API v1** - Online and in-person payments with full lifecycle management
- **Checkout API v3** - Complete checkout sessions for payments and subscriptions
- **Recurring Payments API v3** - Recurring payment agreements and charges
- **Login API v1** - OAuth 2.0 / OpenID Connect authentication

Features
--------

[](#features)

- ✅ **Full API Coverage** - Complete support for ePayment API v1, Checkout API v3, Recurring Payments API v3, and Login API v1
- ✅ **Automatic Token Management** - Access tokens cached and refreshed automatically
- ✅ **Fluent Builders** - Easy-to-use builder interfaces for sessions, agreements, and authorization URLs
- ✅ **System Info Headers** - Optional system information headers for better tracking and support
- ✅ **Type-Safe** - PHP 8.1+ with strict types and full type hints
- ✅ **Error Handling** - Comprehensive exception handling with detailed error information
- ✅ **PSR Compliant** - PSR-3 (Logger), PSR-4 (Autoloading), PSR-12 (Code Style), PSR-18 (HTTP Client)
- ✅ **Well Tested** - 89 unit tests with 187 assertions, 100% pass rate
- ✅ **Code Quality** - PHPStan level 5, Laravel Pint for code style
- ✅ **Environment Support** - Separate test and production configurations
- ✅ **Production Ready** - Comprehensive documentation and examples

Requirements
------------

[](#requirements)

- PHP 8.1 or higher
- ext-json

Installation
------------

[](#installation)

Install via Composer:

```
composer require coretrekas/vipps
```

> **Note:** This package requires PHP 8.1 or higher.

Package Structure
-----------------

[](#package-structure)

The SDK is organized under the `Coretrek\Vipps` namespace:

```
Coretrek\Vipps\
├── VippsClient                  # Main SDK client
├── EPayment\
│   ├── EPaymentApi              # ePayment API methods
│   └── PaymentBuilder           # Fluent builder for payments
├── Checkout\
│   ├── CheckoutApi              # Checkout API methods
│   └── SessionBuilder           # Fluent builder for sessions
├── Recurring\
│   ├── RecurringApi             # Recurring API methods
│   └── AgreementBuilder         # Fluent builder for agreements
├── Login\
│   ├── LoginApi                 # Login API methods
│   └── AuthorizationUrlBuilder  # Fluent builder for OAuth URLs
└── Exceptions\
    └── VippsException           # Exception handling

```

All classes use the `Coretrek\Vipps` namespace prefix.

Quick Start
-----------

[](#quick-start)

### Initialize the Client

[](#initialize-the-client)

```
use Coretrek\Vipps\VippsClient;

$client = new VippsClient(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    subscriptionKey: 'your-subscription-key',
    merchantSerialNumber: 'your-msn',
    testMode: true // Set to false for production
);
```

#### Optional: Set System Information Headers

[](#optional-set-system-information-headers)

You can optionally provide system information that will be sent with all API requests for better tracking and support:

```
$client = new VippsClient(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    subscriptionKey: 'your-subscription-key',
    merchantSerialNumber: 'your-msn',
    testMode: true,
    options: [
        'systemName' => 'MyEcommercePlatform',
        'systemVersion' => '2.1.0',
        'pluginName' => 'VippsPaymentPlugin',
        'pluginVersion' => '1.5.3',
    ]
);

// Or set it later
$client->setSystemInfo(
    systemName: 'MyEcommercePlatform',
    systemVersion: '2.1.0',
    pluginName: 'VippsPaymentPlugin',
    pluginVersion: '1.5.3'
);
```

These headers help Vipps support team identify your integration and provide better assistance.

ePayment API
------------

[](#epayment-api)

The ePayment API is designed for online and in-person payments with full lifecycle management including authorization, capture, refund, and cancellation.

### Create a Payment

[](#create-a-payment)

```
// Simple payment creation
$payment = $client->epayment()->createSimplePayment(
    reference: 'order-12345',
    amount: 10000, // Amount in minor units (100.00 NOK)
    currency: 'NOK',
    userFlow: 'WEB_REDIRECT',
    options: [
        'returnUrl' => 'https://example.com/order/12345/complete',
        'paymentDescription' => 'Order #12345',
    ]
);

// Redirect user to payment page
header('Location: ' . $payment['redirectUrl']);
```

### Create a Payment with Builder (Recommended)

[](#create-a-payment-with-builder-recommended)

```
$payment = $client->epayment()
    ->buildPayment()
    ->amount(10000, 'NOK')
    ->reference('order-12345')
    ->userFlow('WEB_REDIRECT')
    ->returnUrl('https://example.com/order/12345/complete')
    ->paymentDescription('Order #12345')
    ->paymentMethod('WALLET')
    ->customerInteraction('CUSTOMER_NOT_PRESENT')
    ->idempotencyKey('payment-order-12345')
    ->systemInfo('my-shop', '1.0.0', 'vipps-plugin', '1.0.0')
    ->create();

echo "Payment URL: " . $payment['redirectUrl'];
```

### Create a Payment with Receipt

[](#create-a-payment-with-receipt)

```
$orderLines = [
    [
        'name' => 'Premium Socks',
        'id' => 'SOCK-001',
        'totalAmount' => 5000,
        'totalAmountExcludingTax' => 4000,
        'totalTaxAmount' => 1000,
        'unitInfo' => [
            'unitPrice' => 2500,
            'quantity' => '2',
            'quantityUnit' => 'PCS',
        ],
    ],
];

$bottomLine = [
    'currency' => 'NOK',
    'receiptNumber' => 'order-12345',
];

$payment = $client->epayment()
    ->buildPayment()
    ->amount(5000, 'NOK')
    ->reference('order-12345')
    ->userFlow('WEB_REDIRECT')
    ->returnUrl('https://example.com/order/12345/complete')
    ->paymentDescription('Order with receipt')
    ->paymentMethod('WALLET')
    ->receipt($orderLines, $bottomLine)
    ->metadata(['orderId' => 'order-12345', 'customerId' => 'CUST-123'])
    ->create();
```

### Get Payment Details

[](#get-payment-details)

```
$payment = $client->epayment()->getPayment('order-12345');

echo "Payment State: " . $payment['state'];
echo "Amount: " . $payment['amount']['value'] . ' ' . $payment['amount']['currency'];
echo "Authorized: " . $payment['aggregate']['authorizedAmount']['value'];
echo "Captured: " . $payment['aggregate']['capturedAmount']['value'];
```

### Capture a Payment

[](#capture-a-payment)

```
// Capture full amount
$result = $client->epayment()->captureAmount(
    reference: 'order-12345',
    amount: 10000,
    currency: 'NOK',
    headers: ['Idempotency-Key' => 'capture-order-12345']
);

// Or use the detailed method
$result = $client->epayment()->capturePayment('order-12345', [
    'modificationAmount' => [
        'value' => 10000,
        'currency' => 'NOK',
    ],
]);
```

### Refund a Payment

[](#refund-a-payment)

```
// Refund partial amount
$result = $client->epayment()->refundAmount(
    reference: 'order-12345',
    amount: 5000,
    currency: 'NOK',
    headers: ['Idempotency-Key' => 'refund-order-12345']
);

// Or use the detailed method
$result = $client->epayment()->refundPayment('order-12345', [
    'modificationAmount' => [
        'value' => 5000,
        'currency' => 'NOK',
    ],
]);
```

### Cancel a Payment

[](#cancel-a-payment)

```
$result = $client->epayment()->cancelPayment('order-12345');

echo "Payment State: " . $result['state']; // TERMINATED
```

### Get Payment Event Log

[](#get-payment-event-log)

```
$events = $client->epayment()->getPaymentEventLog('order-12345');

foreach ($events as $event) {
    echo $event['name'] . ' at ' . $event['timestamp'] . "\n";
}
```

### QR Code Payment

[](#qr-code-payment)

```
$payment = $client->epayment()
    ->buildPayment()
    ->amount(5000, 'NOK')
    ->reference('order-12345')
    ->userFlow('QR')
    ->qrFormat('IMAGE/SVG+XML')
    ->paymentDescription('QR payment')
    ->paymentMethod('WALLET')
    ->create();

echo "QR Code URL: " . $payment['redirectUrl'];
```

### Push Message Payment

[](#push-message-payment)

```
$payment = $client->epayment()
    ->buildPayment()
    ->amount(7500, 'NOK')
    ->reference('order-12345')
    ->userFlow('PUSH_MESSAGE')
    ->customerPhoneNumber('4712345678')
    ->paymentDescription('Push message payment')
    ->paymentMethod('WALLET')
    ->create();
```

### Payment with Shipping Options

[](#payment-with-shipping-options)

```
$payment = $client->epayment()
    ->buildPayment()
    ->amount(15000, 'NOK')
    ->reference('order-12345')
    ->userFlow('WEB_REDIRECT')
    ->returnUrl('https://example.com/order/12345/complete')
    ->paymentDescription('Order with shipping')
    ->paymentMethod('WALLET')
    ->fixedShipping([
        [
            'type' => 'HOME_DELIVERY',
            'brand' => 'POSTEN',
            'options' => [
                [
                    'id' => 'posten-standard',
                    'name' => 'Standard Delivery',
                    'amount' => ['value' => 9900, 'currency' => 'NOK'],
                    'estimatedDelivery' => '2-3 days',
                ],
                [
                    'id' => 'posten-express',
                    'name' => 'Express Delivery',
                    'amount' => ['value' => 19900, 'currency' => 'NOK'],
                    'estimatedDelivery' => 'Next day',
                ],
            ],
        ],
    ])
    ->profileScope('name email phoneNumber address')
    ->create();
```

Checkout API
------------

[](#checkout-api)

### Create a Payment Session (Checkout API)

[](#create-a-payment-session-checkout-api)

```
// Simple payment session
$session = $client->checkout()->createPaymentSession(
    reference: 'order-12345',
    amount: 10000, // Amount in minor units (100.00 NOK)
    currency: 'NOK',
    options: [
        'paymentDescription' => 'Order #12345',
        'merchantInfo' => [
            'callbackUrl' => 'https://example.com/vipps/callback',
            'returnUrl' => 'https://example.com/order/12345/complete',
            'termsAndConditionsUrl' => 'https://example.com/terms',
        ],
    ]
);

// Redirect user to checkout
header('Location: ' . $session['checkoutFrontendUrl']);
```

### Create a Payment Session with Builder (Recommended)

[](#create-a-payment-session-with-builder-recommended)

```
$session = $client->checkout()
    ->buildPaymentSession()
    ->reference('order-12345')
    ->transaction(10000, 'NOK', 'order-12345', 'Order #12345')
    ->merchantInfo(
        callbackUrl: 'https://example.com/vipps/callback',
        returnUrl: 'https://example.com/order/12345/complete',
        termsAndConditionsUrl: 'https://example.com/terms',
        callbackAuthorizationToken: 'your-secret-token'
    )
    ->prefillCustomer([
        'firstName' => 'John',
        'lastName' => 'Doe',
        'email' => 'john@example.com',
        'phoneNumber' => '+4712345678',
    ])
    ->customerInteraction('CUSTOMER_NOT_PRESENT')
    ->elements('Full')
    ->countries(['NO', 'SE', 'DK'])
    ->idempotencyKey('unique-key-' . time())
    ->systemInfo('my-ecommerce', '1.0.0', 'vipps-plugin', '2.0.0')
    ->create();

echo "Checkout URL: " . $session['checkoutFrontendUrl'];
```

### Get Session Information

[](#get-session-information)

```
$sessionInfo = $client->checkout()->getSession('order-12345');

echo "Session State: " . $sessionInfo['sessionState'];
echo "Payment Method: " . $sessionInfo['paymentMethod'];
```

### Create a Recurring Agreement

[](#create-a-recurring-agreement)

```
$agreement = $client->recurring()
    ->buildAgreement()
    ->legacyPricing(2500, 'NOK') // 25.00 NOK per interval
    ->interval('MONTH', 1)
    ->product('Premium Subscription', 'Access to premium features')
    ->merchantUrls(
        redirectUrl: 'https://example.com/subscription/complete',
        agreementUrl: 'https://example.com/my-subscriptions'
    )
    ->phoneNumber('4712345678')
    ->initialCharge(100, 'NOK', 'Activation fee', 'DIRECT_CAPTURE')
    ->idempotencyKey('agreement-' . time())
    ->create();

// Redirect user to accept agreement
header('Location: ' . $agreement['vippsConfirmationUrl']);
```

### List Agreements

[](#list-agreements)

```
$agreements = $client->recurring()->listAgreements([
    'status' => 'ACTIVE',
    'pageNumber' => 1,
    'pageSize' => 50,
]);

foreach ($agreements as $agreement) {
    echo "Agreement ID: " . $agreement['id'] . "\n";
    echo "Product: " . $agreement['productName'] . "\n";
    echo "Status: " . $agreement['status'] . "\n";
}
```

### Create a Charge

[](#create-a-charge)

```
$charge = $client->recurring()->createCharge(
    agreementId: 'agr_5kSeqz',
    chargeData: [
        'amount' => 2500,
        'transactionType' => 'DIRECT_CAPTURE',
        'description' => 'Monthly subscription - January 2024',
        'due' => '2024-01-01',
        'retryDays' => 5,
        'type' => 'RECURRING',
    ],
    headers: ['Idempotency-Key' => 'charge-jan-2024']
);

echo "Charge ID: " . $charge['chargeId'];
```

### Capture a Reserved Charge

[](#capture-a-reserved-charge)

```
$client->recurring()->captureCharge(
    agreementId: 'agr_5kSeqz',
    chargeId: 'chr_123',
    captureData: [
        'amount' => 2500,
        'description' => 'Capture for January',
    ]
);
```

### Refund a Charge

[](#refund-a-charge)

```
$client->recurring()->refundCharge(
    agreementId: 'agr_5kSeqz',
    chargeId: 'chr_123',
    refundData: [
        'amount' => 2500,
        'description' => 'Customer requested refund',
    ]
);
```

Advanced Usage
--------------

[](#advanced-usage)

### Custom HTTP Client

[](#custom-http-client)

You can provide your own PSR-18 compatible HTTP client:

```
use GuzzleHttp\Client;

$httpClient = new Client([
    'timeout' => 60,
    'verify' => true,
]);

$client = new VippsClient(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    subscriptionKey: 'your-subscription-key',
    merchantSerialNumber: 'your-msn',
    testMode: true,
    options: ['http_client' => $httpClient]
);
```

### Custom Logger

[](#custom-logger)

Integrate with your PSR-3 compatible logger:

```
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('vipps');
$logger->pushHandler(new StreamHandler('path/to/vipps.log', Logger::DEBUG));

$client = new VippsClient(
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    subscriptionKey: 'your-subscription-key',
    merchantSerialNumber: 'your-msn',
    testMode: true,
    options: ['logger' => $logger]
);
```

### Error Handling

[](#error-handling)

```
use Coretrek\Vipps\Exceptions\VippsException;

try {
    $session = $client->checkout()->createPaymentSession(
        reference: 'order-12345',
        amount: 10000,
        currency: 'NOK'
    );
} catch (VippsException $e) {
    echo "Error: " . $e->getMessage() . "\n";
    echo "Status Code: " . $e->getCode() . "\n";

    // Check error type
    if ($e->isValidationError()) {
        echo "Validation error occurred\n";
        print_r($e->getErrorDetails());
    }

    if ($e->isAuthenticationError()) {
        echo "Authentication failed - check your credentials\n";
    }

    if ($e->isNotFoundError()) {
        echo "Resource not found\n";
    }
}
```

Checkout API Examples
---------------------

[](#checkout-api-examples)

### Payment with Logistics Options

[](#payment-with-logistics-options)

```
$session = $client->checkout()
    ->buildPaymentSession()
    ->reference('order-12345')
    ->transaction(10000, 'NOK', 'order-12345', 'Order with shipping')
    ->merchantInfo(
        'https://example.com/callback',
        'https://example.com/return',
        'https://example.com/terms'
    )
    ->logistics([
        'fixedOptions' => [
            [
                'brand' => 'POSTEN',
                'amount' => ['value' => 300, 'currency' => 'NOK'],
                'id' => 'posten-home',
                'priority' => 1,
                'isDefault' => true,
                'description' => 'Home delivery',
            ],
            [
                'brand' => 'POSTEN',
                'amount' => ['value' => 200, 'currency' => 'NOK'],
                'type' => 'PICKUP_POINT',
                'id' => 'posten-pickup',
                'priority' => 2,
                'isDefault' => false,
                'description' => 'Pickup point',
            ],
        ],
    ])
    ->create();
```

### Subscription Session

[](#subscription-session)

```
$session = $client->checkout()
    ->buildSubscriptionSession()
    ->reference('sub-12345')
    ->transaction(100, 'NOK', 'sub-12345', 'Initial charge')
    ->subscription([
        'productName' => 'Premium Membership',
        'amount' => ['value' => 2500, 'currency' => 'NOK'],
        'interval' => ['unit' => 'MONTH', 'count' => 1],
        'merchantAgreementUrl' => 'https://example.com/my-subscriptions',
        'productDescription' => 'Monthly premium membership',
    ])
    ->merchantInfo(
        'https://example.com/callback',
        'https://example.com/return',
        'https://example.com/terms'
    )
    ->create();
```

Recurring API Examples
----------------------

[](#recurring-api-examples)

### Agreement with Campaign

[](#agreement-with-campaign)

```
// Price campaign - reduced price until a date
$agreement = $client->recurring()
    ->buildAgreement()
    ->legacyPricing(3900, 'NOK')
    ->interval('MONTH', 1)
    ->product('News Subscription')
    ->merchantUrls('https://example.com/redirect', 'https://example.com/manage')
    ->phoneNumber('4712345678')
    ->priceCampaign(100, '2024-12-31T23:59:59Z') // 1 NOK until end of year
    ->create();

// Period campaign - fixed price for a period
$agreement = $client->recurring()
    ->buildAgreement()
    ->legacyPricing(3900, 'NOK')
    ->interval('MONTH', 1)
    ->product('News Subscription')
    ->merchantUrls('https://example.com/redirect', 'https://example.com/manage')
    ->phoneNumber('4712345678')
    ->periodCampaign(100, 'WEEK', 4) // 1 NOK for 4 weeks
    ->initialCharge(100, 'NOK', 'Campaign activation', 'DIRECT_CAPTURE')
    ->create();
```

### Variable Amount Agreement

[](#variable-amount-agreement)

```
$agreement = $client->recurring()
    ->buildAgreement()
    ->variablePricing(5000, 'NOK') // User can be charged up to 50 NOK
    ->interval('MONTH', 1)
    ->product('Usage-based Service')
    ->merchantUrls('https://example.com/redirect', 'https://example.com/manage')
    ->phoneNumber('4712345678')
    ->create();
```

### Create Multiple Charges Asynchronously

[](#create-multiple-charges-asynchronously)

```
$charges = [
    [
        'agreementId' => 'agr_123',
        'amount' => 2500,
        'transactionType' => 'DIRECT_CAPTURE',
        'description' => 'January charge',
        'due' => '2024-01-01',
        'retryDays' => 5,
        'type' => 'RECURRING',
    ],
    [
        'agreementId' => 'agr_456',
        'amount' => 2500,
        'transactionType' => 'DIRECT_CAPTURE',
        'description' => 'January charge',
        'due' => '2024-01-01',
        'retryDays' => 5,
        'type' => 'RECURRING',
    ],
];

$result = $client->recurring()->createChargesAsync($charges);
```

Login API Examples
------------------

[](#login-api-examples)

### OAuth 2.0 / OpenID Connect Flow

[](#oauth-20--openid-connect-flow)

```
use Coretrek\Vipps\Login\AuthorizationUrlBuilder;

// Generate secure random values
$state = AuthorizationUrlBuilder::generateState();
$nonce = AuthorizationUrlBuilder::generateNonce();
$codeVerifier = AuthorizationUrlBuilder::generateCodeVerifier();

// Build authorization URL
$authUrl = $client->login()
    ->buildAuthorizationUrl()
    ->clientId('your-client-id')
    ->redirectUri('https://example.com/vipps/callback')
    ->scope(['openid', 'name', 'email', 'phoneNumber', 'address'])
    ->state($state)
    ->nonce($nonce)
    ->pkce($codeVerifier, 'S256')
    ->build();

// Store state, nonce, and code_verifier in session
$_SESSION['oauth_state'] = $state;
$_SESSION['oauth_nonce'] = $nonce;
$_SESSION['oauth_code_verifier'] = $codeVerifier;

// Redirect user to Vipps login
header('Location: ' . $authUrl);
```

### App-to-App Flow

[](#app-to-app-flow)

For mobile apps, you can use the app-to-app flow to redirect users from your app to the Vipps app and back:

```
use Coretrek\Vipps\Login\AuthorizationUrlBuilder;

// Generate secure random values
$state = AuthorizationUrlBuilder::generateState();
$nonce = AuthorizationUrlBuilder::generateNonce();
$codeVerifier = AuthorizationUrlBuilder::generateCodeVerifier();

// Build authorization URL with app-to-app flow
$authUrl = $client->login()
    ->buildAuthorizationUrl()
    ->clientId('your-client-id')
    ->redirectUri('https://example.com/vipps/callback')
    ->scope(['openid', 'name', 'email', 'phoneNumber'])
    ->state($state)
    ->nonce($nonce)
    ->pkce($codeVerifier, 'S256')
    ->requestedFlow('app_to_app')
    ->appCallbackUri('myapp://oauth/callback/vipps')
    ->build();

// Store state, nonce, and code_verifier securely
// Then open the auth URL in the device browser or use a deep link
```

The `requestedFlow('app_to_app')` parameter tells Vipps to use the app-to-app flow, and `appCallbackUri()` specifies the deep link URI where the user will be redirected after authenticating in the Vipps app.

### Handle OAuth Callback

[](#handle-oauth-callback)

```
// In your callback handler
$code = $_GET['code'];
$returnedState = $_GET['state'];

// Verify state to prevent CSRF
if ($returnedState !== $_SESSION['oauth_state']) {
    throw new Exception('Invalid state');
}

// Exchange code for tokens
$tokens = $client->login()->exchangeCodeForTokens(
    code: $code,
    redirectUri: 'https://example.com/vipps/callback',
    options: [
        'code_verifier' => $_SESSION['oauth_code_verifier'],
    ]
);

// Get user information
$userInfo = $client->login()->getUserInfo($tokens['access_token']);

echo "Welcome, " . $userInfo['name'];
echo "Email: " . $userInfo['email'];
echo "Phone: " . $userInfo['phone_number'];
```

### CIBA Flow (Merchant-Initiated Login)

[](#ciba-flow-merchant-initiated-login)

```
// Check if user exists
$userExists = $client->login()->checkUserExists('4712345678');

if ($userExists['exists']) {
    // Initiate authentication
    $auth = $client->login()->initiateCibaAuth(
        loginHint: '4712345678',
        options: [
            'scope' => 'openid name email',
            'bindingMessage' => 'Login to Example App',
            'requested_expiry' => 300,
        ]
    );

    // Poll for token (with proper interval)
    $interval = $auth['interval'];
    $authReqId = $auth['auth_req_id'];

    while (true) {
        sleep($interval);

        try {
            $tokens = $client->login()->pollCibaToken($authReqId);
            // User has authenticated
            break;
        } catch (VippsException $e) {
            // Still waiting for user to approve
            continue;
        }
    }

    $userInfo = $client->login()->getUserInfo($tokens['access_token']);
}
```

### Get OpenID Configuration

[](#get-openid-configuration)

```
// Get OpenID Connect discovery document
$config = $client->login()->getOpenIdConfiguration();

echo "Issuer: " . $config['issuer'];
echo "Authorization Endpoint: " . $config['authorization_endpoint'];
echo "Supported Scopes: " . implode(', ', $config['scopes_supported']);

// Get JWKS for token verification
$jwks = $client->login()->getJwks();
```

Testing
-------

[](#testing)

### Running Tests

[](#running-tests)

```
# Run all tests
composer test

# Run only unit tests
composer test:unit

# Run only integration tests
composer test:integration

# Run with coverage report
composer test:coverage
```

### Code Quality

[](#code-quality)

```
# Run static analysis with PHPStan (level 5)
composer phpstan

# Check code style with Laravel Pint
composer pint:test

# Fix code style issues automatically
composer pint
```

### Integration Tests

[](#integration-tests)

Integration tests require valid Vipps test environment credentials. Set these environment variables:

```
export VIPPS_CLIENT_ID="your-test-client-id"
export VIPPS_CLIENT_SECRET="your-test-client-secret"
export VIPPS_SUBSCRIPTION_KEY="your-test-subscription-key"
export VIPPS_MERCHANT_SERIAL_NUMBER="your-test-msn"

# Run integration tests
composer test:integration
```

> **Note:** Integration tests are skipped by default if environment variables are not set.

API Documentation
-----------------

[](#api-documentation)

For detailed API documentation, visit:

- [Checkout API Guide](https://developer.vippsmobilepay.com/docs/APIs/checkout-api/)
- [Recurring API Guide](https://developer.vippsmobilepay.com/docs/APIs/recurring-api/)
- [Login API Guide](https://developer.vippsmobilepay.com/docs/APIs/login-api/)

Support
-------

[](#support)

- **Issues**: [GitHub Issues](https://github.com/coretrek/vipps/issues)

Contributing
------------

[](#contributing)

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

### Development Setup

[](#development-setup)

```
# Clone the repository
git clone https://github.com/coretrekas/vipps.git
cd vipps

# Install dependencies
composer install

# Run tests
composer test

# Check code quality
composer phpstan
composer pint:test
```

License
-------

[](#license)

This SDK is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for version history.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance71

Regular maintenance activity

Popularity18

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~16 days

Total

7

Last Release

162d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/29a951c4d5299e1375ea57b5d0174981352c2664df175cb4a074a3c0f87128a0?d=identicon)[leitom](/maintainers/leitom)

---

Top Contributors

[![leitom](https://avatars.githubusercontent.com/u/222862?v=4)](https://github.com/leitom "leitom (13 commits)")

---

Tags

sdkoauthrecurringpaymentloginsubscriptioncheckoutvippsmobilepaycoretrek

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/coretrekas-vipps/health.svg)

```
[![Health](https://phpackages.com/badges/coretrekas-vipps/health.svg)](https://phpackages.com/packages/coretrekas-vipps)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M736](/packages/sylius-sylius)[google/auth

Google Auth Library for PHP

1.4k294.2M218](/packages/google-auth)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
