Recurring PSP API guide
Recurring API card passthrough for PSPs is in development and targeted for Q2/Q3 2026.
Overview​
PSPs using the Recurring API process card payments through their own infrastructure using card passthrough. There are three main flows where you receive a card token and must respond with the processing result:
- Agreement sign-up — user selects a card when signing an agreement; you process a CIT.
- Payment source update — user changes their card on an existing agreement; you process a zero-amount CIT.
- Charge — you create a charge and receive card info synchronously in the response; you process the payment and update us asynchronously.
This page covers the PSP-specific card passthrough additions; for full Recurring API documentation, see the Recurring API section.
Agreements​
Unlike direct merchants, PSPs must process the CIT themselves to verify the payment source and confirm the agreement — Vipps MobilePay does not handle this on your behalf. See Agreements in the Recurring API guide for general background.
Charges​
PSPs initially only have access to unscheduled charges — you are responsible for your own retry and scheduling logic. Note that an optional initial charge on the agreement controls the CIT amount during sign-up; if omitted, a zero-amount CIT is performed. See Charges in the Recurring API guide for general background.
Payment sources​
Cards are the only supported payment source for PSPs initially. When a user changes their card on an existing agreement, you receive a zero-amount CIT callback to verify the new card — this flow is PSP-specific and handled entirely through the card callback.
Create an agreement​
Before creating agreements, implement your card callback endpoint. Vipps MobilePay calls it synchronously after the user confirms the agreement and expects a response within 20 seconds.
Agreement sign-up with card passthrough is initiated by sending a draft agreement request with the following settings:
- Add the
Psp-Idheader with your PSP identifier - Include the
cardPassthroughobject, filled outpspReference(required): Your unique reference for the agreement.cardCallbackUrl(required): URL where we will send the card token.cardCallbackAuthHeader(required): Authentication header value for the callback.allowedCardTypes: Card types the user can select. Values:VISA_DEBIT,VISA_CREDIT,VISA_DANKORT,DANKORT,MC_CREDIT,MC_DEBIT. If not specified, all types are allowed.preferVisaPartOfVisaDankort: Whentrue, prefer the Visa part of a Visa/Dankort co-branded card. Default:false.
Example request body:
{
"pricing": {
"type": "LEGACY",
"currency": "NOK",
"amount": 10000
},
"interval": {
"unit": "MONTH",
"count": "1"
},
"initialCharge": {
"amount": 10000,
"description": "First payment",
"transactionType": "DIRECT_CAPTURE"
},
"merchantRedirectUrl": "https://example.com/redirect",
"merchantAgreementUrl": "https://example.com/agreement",
"productName": "Streaming subscription",
"cardPassthrough": {
"pspReference": "subscription-product-123",
"cardCallbackUrl": "https://example.com/psp-callback",
"cardCallbackAuthHeader": "Bearer your-secure-token",
"allowedCardTypes": ["VISA_DEBIT", "VISA_CREDIT", "VISA_DANKORT", "MC_CREDIT", "MC_DEBIT"],
"preferVisaPartOfVisaDankort": true
}
}
Full example
Example request (PSP-specific fields are highlighted):
curl -X POST https://apitest.vipps.no/recurring/v3/agreements/ \
-H "Content-Type: application/json" \
-H "Psp-Id: YOUR-PSP-ID" \
-H "Authorization: Bearer YOUR-ACCESS-TOKEN" \
-H "Ocp-Apim-Subscription-Key: YOUR-SUBSCRIPTION-KEY" \
-H "Merchant-Serial-Number: YOUR-MSN" \
-H 'Idempotency-Key: YOUR-IDEMPOTENCY-KEY' \
-H "Vipps-System-Name: acme" \
-H "Vipps-System-Version: 3.1.2" \
-H "Vipps-System-Plugin-Name: acme-webshop" \
-H "Vipps-System-Plugin-Version: 4.5.6" \
-d '{
"cardPassthrough": {
"pspReference": "subscription-product-123",
"cardCallbackUrl": "https://example.com/psp-callback",
"cardCallbackAuthHeader": "Bearer your-secure-token",
"allowedCardTypes": ["VISA_DEBIT", "VISA_CREDIT", "VISA_DANKORT", "MC_CREDIT", "MC_DEBIT"],
"preferVisaPartOfVisaDankort": true
},
"interval": {
"unit" : "WEEK",
"count": 2
},
"pricing": {
"amount": 1000,
"currency": "NOK"
},
"merchantRedirectUrl": "https://example.com/redirect-url",
"merchantAgreementUrl": "https://example.com/agreement-url",
"phoneNumber": "12345678",
"productName": "Test product"
}'
The optional initialCharge field controls the CIT amount — omit it and a zero-amount CIT is performed instead. Vipps MobilePay forwards the card details to you, and it is your responsibility to process the CIT and respond with the result.
The agreement sign-up flow:
Once the agreement is successfully signed, you can start charging the user according to the agreement terms.
The user may also reject the agreement or abandon the flow — subscribe to agreement webhooks to be notified of these and other events.
For all available fields, see Agreements in the Recurring API guide.
Create a charge​
PSPs only have access to unscheduled charges initially. You are responsible for creating charges according to the terms of each agreement.
Create charges using one of the Recurring API charge endpoints:
POST:/recurring/v3/agreements/{agreementId}/chargesfor single chargesPOST:/recurring/v3/agreements/chargesfor batch charges
Include the Psp-Id header with your PSP identifier.
For example:
curl -X POST https://apitest.vipps.no/recurring/v3/agreements/UNIQUE-AGREEMENT-ID/charges \
-H "Content-Type: application/json" \
-H "Psp-Id: YOUR-PSP-ID" \
-H "Authorization: Bearer YOUR-ACCESS-TOKEN" \
-H "Ocp-Apim-Subscription-Key: YOUR-SUBSCRIPTION-KEY" \
-H "Merchant-Serial-Number: YOUR-MSN" \
-H 'Idempotency-Key: YOUR-IDEMPOTENCY-KEY' \
-H "Vipps-System-Name: acme" \
-H "Vipps-System-Version: 3.1.2" \
-H "Vipps-System-Plugin-Name: acme-webshop" \
-H "Vipps-System-Plugin-Version: 4.5.6" \
-d '{
"amount": 1000,
"description": "Monthly subscription.",
"due": "2026-08-08",
"retryDays": 0,
"transactionType": "DIRECT_CAPTURE",
"orderId": "UNIQUE-ORDERID"
}'
Single charges:
Batch charges:
In both cases, card info is returned directly in the charge creation response — cardPassthrough is not required in the charge request.
Unlike the CIT-based flows (agreement sign-up and payment source updates), you do not respond to a synchronous callback. Instead, after processing the payment you must call the charge update endpoint to report the result asynchronously.
Always send the charge update. Without it, the charge remains unresolved in both our system and the user's app — the user will see a pending charge they cannot act on, which typically leads to confusion and support requests.
For the full range of options available, see Recurring API guide: Charges.
Update a payment source​
Each agreement has an attached payment source that can be changed by the user in the app at any time. The new payment source must be verified with a zero-amount CIT — it is your responsibility to process this transaction. The flow is user-initiated and otherwise identical to agreement sign-up.
The callback payload for a payment source update follows the same format as agreement sign-up. See card callback for the specification.
Card callback​
For the agreement sign-up and payment source update flows, Vipps MobilePay calls your cardCallbackUrl synchronously with the card token after the user confirms. You must respond within 20 seconds.
For charges, card info is returned directly in the charge creation response — no callback is involved, and cardPassthrough is not required in the charge request.
Callback request​
We send a POST request to your cardCallbackUrl with the following properties:
pspReference: Your unique reference for this payment, as provided in the create payment request.authorizationAttemptId: Unique identifier for this authorization attempt.merchantSerialNumber: The merchant serial number for the payment.maskedCardNumber: The masked card number (e.g.,47969485XXXX1234).cardType: The card type (e.g.,VISA-DEBIT).cardIssuedInCountryCode: The ISO 3166-1 alpha-2 country code where the card was issued.paymentInstrument: The type of payment instrument.TOKENindicates a network token is provided.networkToken: Object containing the network token details (whenpaymentInstrumentisTOKEN):number: The token number.cryptogram: The cryptogram for the transaction.expiryMonth: Token expiry month.expiryYear: Token expiry year.tokenType: Token network type (e.g.,VISA).eci: Electronic Commerce Indicator.paymentAccountReference: Stable reference across token renewals.
encryptedPan: Encrypted PAN, when provided instead of a network token.softDeclineCompletedRedirectUrl: URL to redirect to after a soft decline is resolved.
For example:
POST /psp-makepayment HTTP/1.1
Host: example.com
Content-Type: application/json
{
"pspReference": "7686f7788898767977",
"authorizationAttemptId": "3030303thisisaguid",
"merchantSerialNumber": "123456",
"softDeclineCompletedRedirectUrl": "https://vipps.no/mobileintercept?transactionId=123456789&responsecode=OK",
"maskedCardNumber": "47969485XXXX1234",
"cardType": "VISA-DEBIT",
"cardIssuedInCountryCode": "DK",
"paymentInstrument": "TOKEN",
"networkToken": {
"number": "5000000000000000001",
"cryptogram": "aFgdgjdkfgjdFDF=",
"expiryMonth": "03",
"expiryYear": "2030",
"tokenType": "VISA",
"eci": "7",
"paymentAccountReference": "5001BO8B9NXVVIXCT0HAJU98I512Z"
},
"encryptedPan": "xyzxyz"
}
Callback response​
Respond with HTTP 200 OK and a JSON body with the following properties:
status(required): The payment result. One of:RESERVE— Payment reserved successfully.CAPTURE— Payment captured immediately. Use this if processing as a sale, or if you are certain you will capture.FAIL— Payment failed. Include error reason and error codes so we can show a meaningful message to the user.SOFT_DECLINE— Soft decline. IncludesoftDeclineRedirectUrl.
networkTransactionReference: Your reference for the network transaction.
For example:
{
"networkTransactionReference": "123456789",
"status": "RESERVE"
}
If we receive a FAIL response, we will allow the user to retry with the same or a new payment source (unless the error code maps to something non-retryable). More information about error cases and soft decline will come later.
Authentication​
HMAC authentication will be added to the callbacks. More information will come.
Update the payment or agreement information​
TO BE PROVIDED
Related Recurring features​
For the full range of options available on the Recurring API endpoints, see: