Skip to main content

Vipps MobilePay payment handler

Under development

This documentation is under development. Content and integration details may change as we continue internal discussions. Feedback is welcome.

  • Handler Name: com.vippsmobilepay.ucp.payment_handler
  • Version: 2026-01-23

Introduction

This payment handler supports payment creation through the Vipps MobilePay ePayment API. Two payment methods are supported:

  • WALLET - For customers with a Vipps MobilePay wallet. Uses push notification flow (userFlow: PUSH_MESSAGE).
  • CARD - For customers without a wallet. Uses redirect flow (userFlow: WEB_REDIRECT) where users enter card details on the Vipps MobilePay payment page.

Key benefits

  • Efficient integration with Vipps MobilePay payment services.
  • Seamless checkout experience for customers with or without a Vipps MobilePay wallet.
  • Secure handling of payment credentials and transactions.

Integration guide

ParticipantIntegration Section
BusinessBusiness Integration
PlatformPlatform Integration

Participants

This payment handler covers two participants: the business for which a customer is shopping from and the platform that facilitates the checkout process (such as an agent).

  • The business is responsible for processing payments using this handler,
  • The platform offers the supported payment instrument to the customer in the checkout flow.
  • The business registers this handler and configures/implements it, and the platform discovers and utilizes the handler during checkout.
  • The business needs to have an active merchant agreement and an ecommerce sales unit registered with Vipps Mobilepay
  • The platform needs to validate that a user has a valid Vipps Mobilepay identity before offering this payment option. Suggestion is to utilize the Vipps Login Product to do so

Note on Terminology: While this specification refers to the participant as the "business," technical schema fields may retain the standard industry nomenclature merchant_* (e.g., merchant_id). Mappings are documented below.

ParticipantRolePrerequisites
BusinessCreates a payment for the defined customer in the Vipps MobilePay ecosystemNeeds to have an active merchant agreement and ecom sales unit with Vipps Mobilepay
PlatformCollects the customer information, along with validating that the customer has the Vipps wallet.Needs to validate that the user has the Vipps MobilePay wallet

Payment flow diagram

The following diagram shows the async payment flow for this handler. The credential can be either MSISDN (phone number) or TOKEN (customer token):

Platform                    Business                    Vipps                    User
│ │ │ │
│ POST /complete │ │ │
│ (MSISDN or TOKEN) │ │ │
│──────────────────────────>│ │ │
│ │ CreatePayment │ │
│ │ (phoneNumber or │ │
│ │ customerToken) │ │
│ │─────────────────────────>│ │
│ │ state: CREATED │ Push Notification │
│ │<─────────────────────────│───────────────────────>│
│ status: complete_in_progress │ │
│<──────────────────────────│ │ │
│ │ │ │
│ (tells user to check Vipps) │ User Approves │
│ │ │<───────────────────────│
│ │ Callback: AUTHORIZED │ │
│ │<─────────────────────────│ │
│ │ (updates session) │ │
│ │ │ │
│ GET /checkout-sessions/id │ │ │
│──────────────────────────>│ │ │
│ status: completed + order │ │ │
│<──────────────────────────│ │ │

Note: To create a payment, the business MUST create a Vipps Mobilepay Access Token using their credentials and then call the Vipps Mobilepay Epayment API CreatePayments endpoint to create a payment. The suggested payment userFlow is PUSH_MESSAGE, which triggers a push notification to the user's Vipps Mobilepay app to approve the payment.

Business integration

Business prerequisites

Before advertising this handler, businesses MUST complete:

  1. Create a merchant agreement and register an Ecommerce sales unit with Vipps Mobilepay
  2. Implement server-side logic to generate access tokens and create payments using the Vipps Mobilepay AccessToken and ePayment APIs.

Prerequisites Output:

FieldDescription
identity.clientIdThe client id to call the Vipps Mobilepay APIs with
identity.clientSecretThe secret to call the Vipps Mobilepay APIs with
identity.subscriptionKeyThe subscription key to call the Vipps Mobilepay APIs with.
merchant.merchantSerialNumberThe merchant identifier in the Vipps Mobilepay systems

Handler configuration

Businesses advertise support for this handler in their /.well-known/ucp profile under the payment.handlers array.

Configuration schema

Schema URL: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/wallet_payment_handler.json

FieldTypeRequiredDescription
merchant_serial_numberstringYesThe merchant identifier (MSN) in the Vipps MobilePay systems. This is obtained when registering an ecommerce sales unit with Vipps MobilePay. Format varies by country (5-6 digits typically).
environmentenumNoThe Vipps MobilePay environment. One of TEST or PRODUCTION. Defaults to PRODUCTION if not specified. Use TEST for sandbox testing with test credentials.
allowed_payment_instrumentsarrayNoThe payment instruments allowed for this handler. If not specified, all instrument types are allowed. Supported types: WALLET (push notification flow) and CARD (redirect flow).

Example handler declaration

{
"payment": {
"handlers": [
{
"id": "vipps_mobilepay",
"name": "com.vippsmobilepay.ucp.payment_handler",
"version": "2026-01-23",
"spec": "https://ucp.vippsmobilepay.com/ucp/2026-01-23/vipps_mp_payment_handler",
"config_schema": "https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/wallet_payment_handler.json",
"instrument_schemas": [
"https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/payment_instrument.json"
],
"config": {
"merchant_serial_number": "123456",
"environment": "PRODUCTION"
}
}
]
}
}

Instrument schema

Schema URL: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/payment_instrument.json

The Vipps MobilePay payment instrument defines the structure for payments submitted by platforms.

FieldTypeRequiredDescription
typeenumYesThe payment instrument type. One of WALLET or CARD.
credentialobjectYes (WALLET only)The credential information required to process WALLET payments. See Credential Schema.
return_urlstringYes (CARD only)The URL to redirect the user back to after CARD payment. Can be a universal link or website URL.

Instrument types

TypeVipps paymentMethod.typeVipps userFlowDescription
WALLETWALLETPUSH_MESSAGEPush notification to user's Vipps app. Requires customer credential (MSISDN or TOKEN).
CARDCARDWEB_REDIRECTRedirect user to Vipps payment page to enter card details. No wallet required.

Credential schema

Schema URL: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/wallet_payment_credential.json

The credential object contains the buyer's Vipps MobilePay wallet identifier. Two credential types are supported:

FieldTypeRequiredDescription
typeenumYesThe credential type. One of MSISDN or TOKEN.
valuestringYesThe credential value. Format depends on the credential type (see below).
MSISDN credential (public)

The MSISDN credential uses the customer's phone number. This maps to the customer.phoneNumber field in the Vipps ePayment API.

FieldDescription
valueThe phone number in MSISDN format: digits only with country code and subscriber number, no leading zeros or plus sign. Example: 4712345678 for Norwegian number +47 12 34 56 78.

Example MSISDN Instrument:

{
"type": "WALLET",
"credential": {
"type": "MSISDN",
"value": "4712345678"
}
}
TOKEN credential

The TOKEN credential uses an encoded customer token obtained from authenticated user sessions. This maps to the customer.customerToken field in the Vipps ePayment API.

FieldDescription
valueAn encoded customer token string obtained from authenticated sessions.

Example TOKEN Instrument:

{
"type": "WALLET",
"credential": {
"type": "TOKEN",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}

CARD instrument (no wallet required)

The CARD instrument allows customers who do not have a Vipps MobilePay wallet to pay using their card. This uses the redirect flow where the user is sent to the Vipps MobilePay payment page to enter their card details.

FieldTypeRequiredDescription
typeenumYesMust be CARD.
return_urlstringYesThe URL to redirect the user back to after payment. Can be a universal link (e.g., myapp://payment-complete) or website URL (e.g., https://example.com/payment-complete).

Example CARD Instrument:

{
"type": "CARD",
"return_url": "https://chat.vippsmobilepay.com/payment-complete?session_id=cs-ABC123XYZ"
}

Example CARD Instrument with Universal Link:

{
"type": "CARD",
"return_url": "vipps-chat://payment-complete?session_id=cs-ABC123XYZ"
}

Processing payments

Upon receiving a call for completing a checkout with this handler, businesses MUST:

  1. Validate Handler: Confirm instrument.handler_id matches an advertised handler.
  2. Ensure Idempotency: If the request is a retry (matches a previous checkout_id or idempotency key), return the previous result immediately without re-processing funds.
  3. Determine Payment Method: Based on the instrument type:
  • WALLET → Use paymentMethod: { type: "WALLET" } and userFlow: "PUSH_MESSAGE"
  • CARD → Use paymentMethod: { type: "CARD" } and userFlow: "WEB_REDIRECT"
  1. Build Vipps API Request: See WALLET Payment Flow or CARD Payment Flow below.
  2. Call the Vipps ePayment API CreatePayment endpoint.
  3. Return Response: Based on instrument type:
  • WALLET → Return status: complete_in_progress with message to check Vipps app
  • CARD → Return status: complete_in_progress with continue_url for platform to redirect user
  1. Handle Vipps Callback and Poll: When the user approves/rejects, Vipps sends a callback. Update the checkout session accordingly. As callbacks are not guaranteed, implement polling as a backup to check payment status. It is also possible to base this on webhooks if the platform supports that.
  2. Return Completed Order: When the platform polls and payment is authorized, return status: completed with the order.

Vipps API paymentMethod Mapping

The paymentMethod.type field in the Vipps ePayment API MUST match the instrument type:

Instrument TypeVipps paymentMethod.typeVipps userFlowDescription
WALLETWALLETPUSH_MESSAGEPush notification to user's Vipps app
CARDCARDWEB_REDIRECTRedirect to Vipps payment page for card entry

See the Vipps ePayment API documentation for full details on the paymentMethod and userFlow fields.


WALLET payment flow

The Vipps MobilePay PUSH_MESSAGE flow is asynchronous - the user must approve the payment in their Vipps app. This can take seconds to minutes. Businesses MUST NOT block the HTTP response waiting for user approval.

Why async?

ApproachProblem
Block HTTP requestTimeouts after 30s, user often needs more time
Short timeout (5s)User can't approve that fast
Keep connection openUnreliable, poor scalability
  1. Business creates payment → Vipps returns state: CREATED
  2. Business returns immediately with status: complete_in_progress
  3. Vipps sends push notification to user's phone
  4. User approves in Vipps app
  5. Vipps sends callback to business with state: AUTHORIZED
  6. Business updates checkout to status: completed
  7. Platform polls and receives completed order

Complete checkout response (pending approval)

When the payment is created but awaiting user approval:

{
"id": "cs-ABC123XYZ",
"status": "complete_in_progress",
"messages": [
{
"type": "info",
"code": "payment_pending_user_approval",
"content": "A payment request has been sent to your Vipps app. Please open Vipps and approve the payment to complete your order."
}
],
"payment": {
"state": "pending_approval",
"expires_at": "2026-01-26T12:35:00Z"
},
"ucp": {
"version": "2026-01-11",
"capability": "dev.ucp.shopping.checkout"
}
}

Message codes

CodeTypeInstrumentDescription
payment_pending_user_approvalinfoWALLETPayment request sent, awaiting user approval in Vipps app
payment_redirect_requiredinfoCARDUser must be redirected to Vipps payment page to enter card details
payment_approvedinfoBothUser approved/completed the payment
payment_rejectederrorBothUser rejected or cancelled the payment
payment_expirederrorBothPayment request expired before user responded

Timeout handling

Businesses SHOULD implement timeout handling:

  • Default timeout: 5 minutes from payment creation
  • On timeout: Cancel the Vipps payment and set checkout to error state
  • Expose expiry: Include payment.expires_at in responses

Vipps callback handling

Businesses MUST implement a callback endpoint to receive payment status updates from Vipps.

Important: Vipps does not guarantee callback delivery. Businesses MUST also implement polling as a backup. See Vipps Polling Guidelines.

Callback URL: Configured in VippsMerchantInfo.callbackUrl

Callback Payload:

{
"reference": "cs-ABC123XYZ",
"state": "AUTHORIZED",
"pspReference": "1234567890"
}

Callback States:

Vipps StateAction
AUTHORIZEDUpdate checkout to completed, create order
ABORTEDUpdate checkout with error: user rejected
EXPIREDUpdate checkout with error: payment expired
TERMINATEDUpdate checkout with error: payment cancelled

Business-side polling (backup)

Since Vipps callbacks are not guaranteed, businesses MUST implement polling as a backup mechanism to check payment status.

Vipps Polling Guidelines:

  • Start polling: 5 seconds after payment creation
  • Poll interval: Every 2 seconds
  • Endpoint: GET /epayment/v1/payments/{reference}

Example Polling Logic:

async function pollVippsPaymentStatus(reference: string, maxAttempts = 150) {
const POLL_INTERVAL_MS = 2000; // 2 seconds
const INITIAL_DELAY_MS = 5000; // 5 seconds

// Wait 5 seconds before starting
await new Promise(resolve => setTimeout(resolve, INITIAL_DELAY_MS));

for (let attempt = 0; attempt < maxAttempts; attempt++) {
const payment = await getVippsPayment(reference);

if (payment.state === "AUTHORIZED") {
// Payment approved - complete the order
return { success: true, state: "AUTHORIZED" };
}

if (["ABORTED", "EXPIRED", "TERMINATED"].includes(payment.state)) {
// Payment failed - update checkout with error
return { success: false, state: payment.state };
}

// Still CREATED - wait and poll again
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
}

// Timeout - treat as expired
return { success: false, state: "TIMEOUT" };
}

Note: The callback and polling mechanisms are complementary. Whichever receives the status update first should process it, and the other should recognize that processing has already occurred (idempotency).


CARD payment flow (redirect)

The CARD payment flow uses WEB_REDIRECT user flow. The user is redirected to the Vipps MobilePay payment page to enter their card details. This flow is for customers who do not have a Vipps MobilePay wallet.

CARD flow diagram

Platform                    Business                    Vipps                    User
│ │ │ │
│ POST /complete │ │ │
│ (type: CARD, return_url) │ │ │
│──────────────────────────>│ │ │
│ │ CreatePayment │ │
│ │ (paymentMethod: CARD, │ │
│ │ userFlow: WEB_REDIRECT, │ │
│ │ returnUrl) │ │
│ │─────────────────────────>│ │
│ │ state: CREATED │ │
│ │ + redirectUrl │ │
│ │<─────────────────────────│ │
│ status: complete_in_progress │ │
│ + continue_url │ │ │
│<──────────────────────────│ │ │
│ │ │ │
│ (redirects user) │ │ │
│───────────────────────────────────────────────────────────────────────────────>│
│ │ │ User enters card │
│ │ │<───────────────────────│
│ │ Callback: AUTHORIZED │ │
│ │<─────────────────────────│ │
│ │ │ Redirect to returnUrl │
│<───────────────────────────────────────────────────────────────────────────────│
│ │ │ │
│ GET /checkout-sessions/id │ │ │
│──────────────────────────>│ │ │
│ status: completed + order │ │ │
│<──────────────────────────│ │ │

CARD-specific request fields

When creating a payment with paymentMethod: { type: "CARD" }, the business MUST include:

FieldDescription
paymentMethod.typeMUST be CARD
userFlowMUST be WEB_REDIRECT
returnUrlThe URL to redirect the user back to after payment. Use the return_url from the instrument.

CARD business response

When the payment is created, Vipps returns a redirectUrl. The business MUST return this to the platform as continue_url per the UCP Continue URL specification.

The continue_url enables checkout handoff from platform to business UI, allowing the buyer to complete the payment on the Vipps MobilePay payment page. Per UCP, when status is complete_in_progress, the business is processing the Complete Checkout request and may provide a continue_url for user interaction.

{
"id": "cs-ABC123XYZ",
"status": "complete_in_progress",
"continue_url": "https://api.vipps.no/checkout/v3/session/...",
"messages": [
{
"type": "info",
"code": "payment_redirect_required",
"content": "Please complete your payment on the Vipps MobilePay payment page."
}
],
"payment": {
"state": "pending_redirect",
"expires_at": "2026-01-26T12:35:00Z"
}
}

Platform redirect handling

When the platform receives a complete_in_progress response with a continue_url and message code payment_redirect_required:

  1. Redirect the user: Open the continue_url in a browser or webview to hand off to the Vipps payment page
  2. User completes payment: User enters card details on the Vipps payment page
  3. Return redirect: After payment, Vipps redirects user to the returnUrl provided in the instrument
  4. Poll for completion: After redirect, poll GET /checkout-sessions/{id} to get the final status (completed or error)

Return URL Formats:

TypeExampleUse Case
Universal Linkvipps-chat://payment-complete?session_id=cs-ABC123XYZNative mobile app
Website URLhttps://chat.vippsmobilepay.com/payment-complete?session_id=...Web-based chat or fallback

Note: The returnUrl should include sufficient context (e.g., session_id) for the platform to resume the checkout flow after the user returns.


Example business implementation

const instrument: PaymentInstrument; // The payment instrument from the request
const checkout: Checkout; // The checkout with lineItems
const vippsCredentials: VippsCredentials; // Vipps Credentials
const accessToken: string; // The accessToken you received from Vipps
const idempotencyKey: string; // Your idempotency key

const url = "https://apitest.vipps.no/epayment/v1/payments"; // Replace for production

/**
* Build the Vipps API request body based on instrument type.
* See: https://developer.vippsmobilepay.com/api/epayment/#tag/CreatePayments/operation/createPayment
*/
function buildVippsPaymentRequest(instrument: PaymentInstrument, checkout: Checkout) {
const baseRequest = {
amount: {
currency: checkout.currency,
value: checkout.totals.amount
},
reference: checkout.id,
paymentDescription: `Order ${checkout.id}`
};

if (instrument.type === "WALLET") {
// WALLET: Use PUSH_MESSAGE flow with customer credential
return {
...baseRequest,
customer: buildCustomerObject(instrument.credential),
paymentMethod: {
type: "WALLET" // REQUIRED for WALLET instruments
},
userFlow: "PUSH_MESSAGE"
};
} else if (instrument.type === "CARD") {
// CARD: Use WEB_REDIRECT flow, no customer credential needed
return {
...baseRequest,
paymentMethod: {
type: "CARD" // REQUIRED for CARD instruments
},
userFlow: "WEB_REDIRECT",
returnUrl: instrument.return_url // Platform provides this for redirect back
};
}

throw new Error(`Unsupported instrument type: ${instrument.type}`);
}

/**
* Build the customer object for WALLET payments based on credential type.
*/
function buildCustomerObject(credential: WalletCredential): { phoneNumber?: string; customerToken?: string } {
switch (credential.type) {
case "MSISDN":
return { phoneNumber: credential.value };
case "TOKEN":
return { customerToken: credential.value };
default:
throw new Error(`Unsupported credential type: ${credential.type}`);
}
}

const body = buildVippsPaymentRequest(instrument, checkout);

const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${accessToken}`,
"Ocp-Apim-Subscription-Key": vippsCredentials.subscriptionKey,
"Merchant-Serial-Number": vippsCredentials.merchantSerialNumber,
"Idempotency-Key": idempotencyKey
},
body: JSON.stringify(body)
});

const payment = await response.json();

if (!response.ok) {
return mapVippsErrorToUCPResponse(response.status, payment);
}

// Build response based on instrument type
checkout.status = "complete_in_progress";
checkout.payment = {
vipps_reference: payment.reference,
expires_at: new Date(Date.now() + 5 * 60 * 1000).toISOString()
};

if (instrument.type === "WALLET") {
// WALLET: Return message to check Vipps app
checkout.payment.state = "pending_approval";
checkout.messages = [{
type: "info",
code: "payment_pending_user_approval",
content: "A payment request has been sent to your Vipps app. Please open Vipps and approve the payment."
}];
} else if (instrument.type === "CARD") {
// CARD: Return continue_url for platform to redirect user (per UCP spec)
checkout.payment.state = "pending_redirect";
checkout.continue_url = payment.redirectUrl; // From Vipps response, returned as continue_url
checkout.messages = [{
type: "info",
code: "payment_redirect_required",
content: "Please complete your payment on the Vipps MobilePay payment page."
}];
}

return checkout;

TypeScript Types:

type InstrumentType = "WALLET" | "CARD";
type CredentialType = "MSISDN" | "TOKEN";

interface WalletCredential {
type: CredentialType;
value: string;
}

interface WalletInstrument {
type: "WALLET";
credential: WalletCredential;
}

interface CardInstrument {
type: "CARD";
return_url: string; // Universal link or website URL
}

type PaymentInstrument = WalletInstrument | CardInstrument;

// Example Vipps API payloads:

// WALLET with MSISDN -> paymentMethod.type: "WALLET", customer.phoneNumber
const walletMsisdnPayload = {
paymentMethod: { type: "WALLET" },
userFlow: "PUSH_MESSAGE",
customer: { phoneNumber: "4712345678" },
// ... other fields
};

// WALLET with TOKEN -> paymentMethod.type: "WALLET", customer.customerToken
const walletTokenPayload = {
paymentMethod: { type: "WALLET" },
userFlow: "PUSH_MESSAGE",
customer: { customerToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." },
// ... other fields
};

// CARD -> paymentMethod.type: "CARD", no customer field needed
const cardPayload = {
paymentMethod: { type: "CARD" },
userFlow: "WEB_REDIRECT",
returnUrl: "vipps-chat://payment-complete?session_id=cs-ABC123XYZ",
// ... other fields
};

NOTE: For the CardInstrument, the returnUrl must be exactly the same as provided by the platform, to ensure the customer is successfully redirected back to the platform after payment approval.

Error handling

Businesses MUST follow UCP Checkout error handling: return error messages in the checkout messages array only when the platform or buyer can act on them. The severity field declares who resolves the error:

  • recoverable — The platform can fix via API (e.g. correct payment data and retry). Use for invalid instrument data the platform can correct.
  • requires_buyer_input — The business requires input that cannot be provided via API (e.g. buyer must install or link a wallet). Contributes to status: requires_escalation; platform should hand off via continue_url.

Do not return UCP error messages for implementation or backend errors on the business side (e.g. merchant misconfiguration, auth failure, Vipps internal errors). The platform cannot resolve these; the checkout should be discarded or set to a terminal state. The business may handle such errors server-side (retries, alerts, logging) at their discretion.

Map Vipps MobilePay ePayment API errors (RFC 7807, extraDetails error code when present) using the table below. If the error does not appear in the mapping, treat it as a business-side/implementation error: do not surface it as a UCP message to the platform; handle server-side and treat the checkout as non-recoverable.

Note: This mapping covers only payment creation and UCP payment-handling flows.

HTTP StatusVipps Error CodeContext (Vipps title / description)UCP Error CodeUCP SeverityUser-Facing Message
400Request body validation (no error code)invalid_payment_datarecoverableThe payment request contains invalid data. Please verify and try again.
4004050Invalid CustomerTokeninvalid_customer_tokenrecoverableThe provided customer information is invalid. Please validate and try again.
4004070Invalid phone numberinvalid_phonerecoverableThe provided phone number is invalid.
4007010Customer not foundwallet_not_foundrecoverableNo wallet account found for the provided identifier. Please try a different payment method.

For wallet_not_found and invalid_phone, the business has no continue_url to redirect to (the buyer cannot “fix” the wallet link in business UI). The platform should treat these as recoverable—e.g. offer another payment method such as CARD, or prompt the user to try a different identifier.

Important: Error messages returned to platforms should be opaque and user-friendly. Do not expose internal Vipps API error details. Log detailed errors server-side for debugging.

Example UCP Error Response (e.g. for 7010 Customer not found):

{
"messages": [
{
"type": "error",
"code": "wallet_not_found",
"severity": "recoverable",
"content": "No wallet account found for this phone number. Please try a different payment method.",
"path": "$.payment.instruments[0]"
}
]
}

Platform integration

Platform prerequisites

Before using this handler, Platforms MUST complete:

  1. If applicable: Register with merchant to allow to call their checkout_sessions endpoint. This could involve getting an access token
  2. Obtain a valid customer identifier based on the credential type:
  • MSISDN: Capture the user's MSISDN registered with Vipps MobilePay. A suggestion is to implement the Vipps Login Product in your application.
  • TOKEN: Obtain a customer token from an authenticated session.

Prerequisites Output:

FieldDescription
merchant.access_tokenAccess token to call merchant (if applicable)
vippsUser.msisdnVipps user MSISDN registered on their wallet (for MSISDN credential)
vippsUser.customerTokenEncoded customer token from authenticated session (for TOKEN credential)

Payment protocol

Platforms MUST follow this flow to acquire a payment instrument:

Step 1: Discover handler

The Platform identifies com.vippsmobilepay.pay.payment_handler in the business's payment.handlers array.

{
"id": "vipps_mobilepay",
"name": "com.vippsmobilepay.pay.payment_handler",
"version": "2026-01-23",
"config": {
"merchant_serial_number": "123456",
"environment": "PRODUCTION"
}
}

Step 2: Choose payment method and gather required data

The Platform MUST determine which payment method to use based on whether the customer has a Vipps MobilePay wallet:

Option A: WALLET (User has Vipps MobilePay wallet)

For users with a Vipps MobilePay wallet, use the WALLET instrument. The Platform MUST obtain a customer identifier:

  • MSISDN: Prompt the user for their MSISDN registered with Vipps MobilePay. Use the Vipps Login Product to authenticate and retrieve the MSISDN.
  • TOKEN: Use an encoded customer token obtained from an authenticated session.
Option B: CARD (User does not have Vipps MobilePay wallet)

For users without a Vipps MobilePay wallet, use the CARD instrument. The Platform MUST provide:

  • return_url: The URL to redirect the user back to after payment. This can be:
  • Universal Link: e.g., vipps-chat://payment-complete?session_id=... (for native mobile apps)
  • Website URL: e.g., https://chat.vippsmobilepay.com/payment-complete?session_id=... (for web-based platforms)

Tip: Include the checkout session ID in the return URL so the platform can resume the checkout flow after redirect.

Step 3: Complete checkout

The Platform submits the checkout with the constructed payment instrument.

Example with MSISDN credential:

POST /checkout-sessions/{checkout_id}/complete
Content-Type: application/json

{
"payment_data": {
"id": "instr_vipps_1",
"handler_id": "vipps_mobilepay",
"type": "WALLET",
"credential": {
"type": "MSISDN",
"value": "4712345678"
}
},
"risk_signals": {
"device_id": "device_abc123",
"session_id": "session_xyz789",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0 ...",
"accept_language": "nb-NO"
}
}

Example with TOKEN credential:

POST /checkout-sessions/{checkout_id}/complete
Content-Type: application/json

{
"payment_data": {
"id": "instr_vipps_1",
"handler_id": "vipps_mobilepay",
"type": "WALLET",
"credential": {
"type": "TOKEN",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
}

Example with CARD instrument (No wallet required):

POST /checkout-sessions/{checkout_id}/complete
Content-Type: application/json

{
"payment_data": {
"id": "instr_card_1",
"handler_id": "vipps_mobilepay",
"type": "CARD",
"return_url": "vipps-chat://payment-complete?session_id=cs-ABC123XYZ"
}
}

Step 4: Handle async response

Both WALLET and CARD flows return status: complete_in_progress. The Platform MUST handle the response based on the message code:

WALLET Response (pending user approval in Vipps app):

{
"id": "cs-ABC123XYZ",
"status": "complete_in_progress",
"messages": [
{
"type": "info",
"code": "payment_pending_user_approval",
"content": "A payment request has been sent to your Vipps app. Please open Vipps and approve the payment to complete your order."
}
],
"payment": {
"state": "pending_approval",
"expires_at": "2026-01-26T12:35:00Z"
}
}

CARD Response (redirect required):

{
"id": "cs-ABC123XYZ",
"status": "complete_in_progress",
"continue_url": "https://api.vipps.no/checkout/v3/session/...",
"messages": [
{
"type": "info",
"code": "payment_redirect_required",
"content": "Please complete your payment on the Vipps MobilePay payment page."
}
],
"payment": {
"state": "pending_redirect",
"expires_at": "2026-01-26T12:35:00Z"
}
}

Platform behavior for WALLET (payment_pending_user_approval):

  1. Inform the user: Display the message content (e.g., "Please check your Vipps app to approve the payment")
  2. Poll for completion: Call GET /checkout-sessions/{checkout_id} every 2-5 seconds
  3. Check status: Continue polling until status is completed or an error state
  4. Handle timeout: If payment.expires_at passes, inform user the payment expired

Platform behavior for CARD (payment_redirect_required):

Per the UCP Continue URL specification, the continue_url enables checkout handoff from platform to business UI:

  1. Redirect the user: Open the continue_url in a browser or webview to hand off to the Vipps payment page
  2. User completes payment: User enters card details on the Vipps payment page
  3. Handle return: After payment, Vipps redirects user back to the return_url provided in the instrument
  4. Resume checkout: Extract session ID from URL and poll GET /checkout-sessions/{id} for final status (completed or error)

Step 5: Poll for completion

GET /checkout-sessions/{checkout_id}

Response when payment is approved:

{
"id": "cs-ABC123XYZ",
"status": "completed",
"order": {
"id": "order-789",
"reference": "ORD-2026-001234",
"created_at": "2026-01-26T12:32:15Z"
},
"messages": [
{
"type": "info",
"code": "payment_approved",
"content": "Payment approved. Your order has been placed."
}
]
}

Response when user rejects:

{
"id": "cs-ABC123XYZ",
"status": "incomplete",
"messages": [
{
"type": "error",
"code": "payment_rejected",
"severity": "requires_buyer_input",
"content": "Payment was declined. Please try again or choose a different payment method."
}
]
}

Polling best practices

RecommendationDetails
Poll interval2-5 seconds initially, increase if many retries
Max durationStop after payment.expires_at + small buffer
Exponential backoffConsider increasing interval after 30 seconds
User feedbackShow progress indicator while polling

Security considerations

RequirementDescription
TLS RequiredAll communication with the Vipps MobilePay API MUST use TLS 1.2 or higher. Connections using older TLS versions will be rejected.
MSISDN ValidationFor MSISDN credentials, the value MUST be validated to ensure it is a valid phone number format (digits only, 7-15 digits, no leading zero) before sending to the Vipps MobilePay API.
TOKEN ValidationFor TOKEN credentials, the value MUST be validated to ensure it is a non-empty string. Token validity is verified by the Vipps MobilePay API.
Data ResidencyAll payment data is processed within the EEA (European Economic Area). PII is handled according to GDPR requirements.

References

  • Handler Spec: https://ucp.vippsmobilepay.com/ucp/2026-01-23/vipps_mp_payment_handler
  • Config Schema: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/wallet_payment_handler.json
  • Instrument Schema: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/payment_instrument.json
  • Credential Schema: https://ucp.vippsmobilepay.com/ucp/2026-01-23/schemas/wallet_payment_credential.json