Api Authentication

API Key Auth: scheme that uses a unique key for credentials


Authorization Header: the HTTP header used to hold credentials

API Version Status

Active An active API version is the most current and fully supported API. It is the recommended version to use by everyone.
Deprecated:  A deprecated API version has been superseded by a newer API version. It is supported (bug fixes) for six months from the deprecation date. New apps will be denied access to deprecated APIs.
Retired A retired API version is no longer supported. It includes any API deprecated for more than six months. Any application using a retired API must migrate to an active API.

client ID

  • A piece of information that identifies an individual application. An application can invoke an API only if it passes an application key that is recognized by the system and is granted access to the API. The application key is passed by the client by using an HTTP query parameter.

client secret

  • Our APIs are configured to require that client applications supply their client secret 
  • The application secret functions effectively as a password known only to the application.
  • The application secret is passed by the client by using an HTTP query parameter.


The client ID and client secret are auto generated when you create an app in the MobilePay Developer Portal on https://developer.mobilepay.dk/application

  • MobilePay does not require merchants to whitelist specific IP addresses to access REST APIs.
  •  We utilize IPs in two ranges:
    • and 
  • MobilePay uses port 443 

I have forgotten my application client secret. How can I reset it?

Your application client secret is stored encrypted so we cannot retrieve the unencrypted version to tell you the value if you forget it.

You can reset it, which will update the stored value and return the new value to you.

To do that click 'My Apps' in the main menu (after you have logged in), click on the application in question and then you can click the 'Reset' link in the 'Client Secret' section.

Your new secret will be displayed at the top of the page.


You should use orderId when calling the AppSwitch API

The MobilePay AppSwitch SDK accepts an orderId of two characters. Unfortunately, the REST API is a bit different, and it requires 4 characters as a minimum. 

In order to use both the SDK and REST API, you need to use at least 4 characters in your OrderId. 

You can find the endpoints for AppSwitch on our developer portal here  

We have an example of a call to the Payment Status endpoint https://github.com/MobilePayDev/MobilePay-AppSwitch-API/blob/master/REST%20APIs/v1/payment%20status%20interface%20description.md

You should use orderId when calling the AppSwitch API

The AuthenticationSignature should be generated based on your private key. We have registered that public key in our system. The public key is needed in order to complete the onboarding. Please send the public key in a zip file or as a plain text. Our mail server is very sensitive. 

Below you can find examples of how to create the signed payload used in the AuthenticationSignature header

Please read the Technical documentation here on how to get onboarded and start using MobilePay AppSwitch API. 

In order to get access to the AppSwitch API, you need to create a user on https://developer.mobeco.dk/.

You can find the documentation on  GitHub or on our Developer Portal.



  • A Danish/Finnish/Norwegian VAT ​identification​ number
  • A MobilePay AppSwitch agreement
  • A native app (MobilePay AppSwitch supports native apps for iOS, Android and Windows Phone)
  • Compliance with the rules and regulation for in-app puchases set by Apple, Google and Windows.

To use MobilePay AppSwitch, all services and products sold through the app need to be consumed outside the app. This means that MobilePay AppSwitch cannot be used for sale of digital products and services that are used in the app. 
It is your responsibility to make sure that MobilePay AppSwitch can be and is allowed to be used in relation to the merchant app. It is up to the merchant to make sure that the rules and regulations that apply for the merchant app and sales from the merchant app are complied with - including rules which the app stores (e.g. Apple, Google, Windows) at any time put forward for development and use of merchant apps.

​At our repository on GitHub you can always find an updated list of operating systems supported by the MobilePay AppSwitch SDK.

MobilePay AppSwitch supports native apps for iOS and Android. Using the AppSwitch SDK's should be possible on various cross-platforms as well, however we do not test the SDK's on any cross platforms, or provide support for it in any way or form.

You can see the other platforms, that various developers have integrated on our GitHub here 

​Yes, we have developed a Capture Amount API, which allows you to capture reservations that are made using the SDK. An AppSwitch reservation will expire after 7 days, if it doesn't get handled. Handling is done by the merchant by either withdrawing the money and thus completing the purchase or by cancelling the reservation.

The reservation itself should in principle be canceled when the merchant knows that they will never complete the purchase / withdrawal. It is therefore the merchants responsibility to delete reservations. A nice solution would be to implement a cleanup job that continuously looks at active reservations on Merchant AppSwitch Agreement and delete the relevant reservations. 

​Yes, we have developed a Refund Amount API, which allows you to make either full or partial refunds directly from your own systems.

To ensure a good user experience, you must thoroughly test your app before launching MobilePay. All information related to test is gathered here. We recommend that you read the information on the site and go through the test cases.

However, it is possible to use the test merchant ids to simulate a payment flow without doing any real payments.

The test merchant ids are APPDK0000000000 for Danish version of MobilePay and APPFI0000000000 for Finnish version of MobilePay.

The MobilePay AppSwitch backend is based on REST API's and can be used by practically any programming language​.

All information related to test is gathered here. We recommend that you read the information on the site.

​When the requested payment has been completed in MobilePay, a signed payment ticket is returned to the merchant app. The signed information contains the original merchant order ID and the MobilePay transaction ID. The MobilePay SDK validates the signature and ensures that the order ID given to the MobilePay SDK by the merchant app matches the order ID received from MobilePay.

Yes, you can create as many ID’s as you need. The IDs can be connected to one or more of your accounts depending on your preferences.

No, MobilePay AppSwitch can be used for person-to-business transactions only.


To use and integrate the API's requires basic familiarity with software development, web services, and the MobilePay app user interface. Read more here


You'll find them here  for both FI and DK. If there is an issue with a test user, please try a different user, or contact us at developer@mobilepay.dk

Please note, that all test users have a daily payment limit, and therefore we recommend that you use small amounts, when testing payments.

General testing 

To ensure a good user experience, we recommend you to test your solution thoroughly before launching, and for each product there is different testing.  Read more:

You'll find them under the NEWS  section. This is also where you can subscribe to the Release Notes, so you'll receive an e-mail when we have release notes. 

If you want to try to call the REST api, then you can try our HELLO API  

What is it? 

Partnerbanks and merchants can use this API to test the onboarding and get familiar with our API's.  There is no authentication here, or a SSL certificate you need to think about. You only need a log-in to the developer portal, and that is it! 

What is the next action?

In order to create a profile, please write to developer@mobilepay.dk in order to receive the invitation e-mail to the Developer Portal. When you've done so, you will proceed to do the following:

  1. log-in. There are two urls: sandbox   and production
  2. Create App: To register an app, On the My Apps page, click Create App.   

Calling the API 

Once your app is created on the Developer Portal and you have your credentials you're able to connect to our API. Perform a GET request to our API endpoints

You'll need to include the following headers:

 accept: application/json
 content-type: application/json
 x-ibm-client-id: REPLACE_THIS_KEY
 x-ibm-client-secret: REPLACE_THIS_KEY

If the request is successful, you will receive a HTTP 200 OK Status Code, and a JSON body:

    "Message": "Hello!"

If you have any questions, please write to our Developer team at developer@mobilepay.dk

You can read about REST API errors in the REST API reference that are found within each API here. This list can help you anticipate and account for most errors. 

General - Glossary

Our API Versioning strategy is based on industry standards, which would implicitly apply. You can read more about semantic versioning at these sources:

JSON: JavaScript Object Notation. JSON is a syntax for storing and exchanging data. JSON is text, written with JavaScript object notation. Since the JSON format is text only, it can easily be sent to and from a server, and used as a data format by any programming language.


Postman is a REST client for testing APIs. It allows the user  to send requests, save responses, add tests, and create workflows. You can learn more about Postman here and learn how to use postman to test APIs here


Rely on standard HTTP codes to convey basic status information and errors in responses.

There are over 70 status codes to describe the return value. The following is a list of the most common ones, but others may also be applicable in different contexts.


Status Code


2xx – Success

200 OK

The request was successfully executed


201 OK

New resource has been created


204 OK

The resource was successfully deleted

3xx – Redirection

304 Not modified

The client can use cached data

4xx – Client error

400 Bad Request

The request failed, e.g., validation error


401 Unauthorized

Bad credentials, e.g., missing authentication


403 Forbidden

Access denied, e.g., missing authorization


404 Not found

URI does not map to a resource

5xx – Server error

500 Internal server error 

API malfunction, e.g., hard system or database error 

The most commonly used ones include:

POST: Create a new resource based on the data provided, or submit a command
PUT: Replace content of an existing resource
GET: Retrieve the current value of a resource – must not have side effects
DELETE: Delete an existing resource

In addition, PATCH can be used to perform a partial update of an existing resource

The commonly used HTTP request headers are:

Header Description

Required for operations with a response body.

Specifies the response format. The syntax is:

Accept: application/json

Required to get an access token or make API calls.

To get an access token, set this header to your client_id and secret credentials.

To make REST API calls, include the bearer token in the Authorization header with the Bearer authentication scheme:

Authorization: Bearer Access-Token

Required for operations with a request body.

Specifies the request format. The syntax is:

Content-Type: application/json

A named thing in a namespace, such as a payment transaction, against which you call REST methods.

For example:


To construct a REST API request, combine these components

Component Description

The HTTP method

  • GET. Requests data from a resource.
  • POST. Submits data to a resource to process.
  • PUT. Updates a resource.
  • PATCH. Partially updates a resource.
  • DELETE. Deletes a resource.

The URL to the API service

  • Sandbox. https://api.sandbox.mobilepay.dk
  • Production. https://api.mobilepay.com

The URI to the resource

The resource to query, submit data to, update, or delete. For example, v1/merchants/{merchantid}/invoiceissuers.

Query parameters

Optional. Controls which data appears in the response. Use to filter, limit the size of, and sort the data in an API response.

HTTP request headers

Includes the Authorization header with the access token.

A JSON request body

Required for most GETPOSTPUT, and PATCH calls.

The use of pagination parameters to limit the size of and sort the data returned in an API response. A pagination parameter is a type of query parameter, which is a type of parameter that you include on the request URI to filter and sort the items, that are returned in an API response and limit the size of the data returned in that response. 


The URL through which you access an API. For example:


General - Sandbox

Confirm an e-mail address in the MobilePay sandbox.

Note: Accounts that are created from the developer@mobilepay.dk are not automatically confirmed. You need to activate your profile in 7 days 

For accounts that are created by developer@mobilepay.dk 

  1. Receive e-mail from developer@mobilepay.dk 
  2. Log into the sandbox developer portal  

Complete the steps to link your sandbox account to your e-mail account 

We have two environments, which you'll use for different purposes. You'll use the sandbox developer portal, when you're testing. You'll use the production developer portal, when you've completed testing in sandbox, and are ready to handle real payments in production. During your testing phase, use the Sandbox endpoints and your test account details in each MobilePay API request you make. 

The sandbox URL is 


The production URL is



There are 2 types of log-ins you will encounter when doing MobilePay integration:

Log-in for MobilePay - Developer Portal 

  • Sandbox: Invite will be send by Developer Support. In sandbox you will create an app and that will autogenerate another set of credentials (client-id and client-secret) for the Sandbox API - these must be used for authorisation when calling the Sandbox API.  Password for the developer portal is created by you, so if you forget your password, you should request a new password:https://sandbox-developer.mobilepay.dk/user/password
  • Production: Same as for the Sandbox.  
 Login for MobilePay Administration Portal
  • Sandbox: MobilePay will provide you with a test merchant with dummy data. On the test merchant you can set up subscription providers and invoice issuers (payment points) as well as download a list of payments for your product.
  • Production: When you sign up for MobilePay Subscriptions or Invoice you create login with your own e-mail and password. In production you have the same options as in Sandbox

  Credentials for OpenID Connect (OIDC).

These are used to grant you access to the Authorisation server

  • Sandbox: MobilePay will provide you with credentials (ClientId and ClientSecret) in a password protected zip file. These credentials must be used when going through the OIDC process to obtain tokens from MobilePay. The password to the zip file is sent via SMS. 
  • Production: Same as for the sandbox.

Sandboxes are isolated from your production organisation, so operations that you perform in the MobilePay sandbox don’t affect your production organisation. The production version of the API provides access to the real customer data, i.e. you will be able to initiate real payments. 

Once you go to test in production, you will use another basepath, the live MobilePay app and a real MobilePay user.

Difference between sandbox and production 

  Sandbox Production
User Test users. Find them here A real MobilePay user, that has downloaded the MobilePay app on their smartphone
Payment limit Same as in production. Read here Read here
User simulation

There isn't a sandbox app for MobilePay. Instead, use the following API's to simulate user interaction:

  • Invoice User Simulation
  • Subscriptions User Simulation 

It processes API calls in exactly the same manner as does the Production environment, except you are not dealing with real transactions

Endpoint https://api.mobilepay.dk
MobilePay Portal https://admin.mobilepay.dk
Supported endpoints in OpenID Connect 
Find the supported endpoints for sandbox here
Find the supported endpoints for production here
Payment Validation for Subscriptions
1 day
8 days 

MobilePay makes payment batches daily in Sandbox environment. Certain validations are removed in Sandbox to enable quicker testing etc. In the Production environment, subscriptions payments must be requested at least 8 days before due date, otherwise the payment will be declined. 


The behavior of the API when you are in sandbox mode is the same as when your app is live, but comes with the following restrictions: The users in the Sandbox have a daily limit at 3.000 DK. It is recommended to send Payment Requests within <10 DKK. It depends on the way the customer is validated in MobilePay. For details about the payment limit, see "Beløbsgrænse" : https://mobilepay.dk/da-dk/help/privat/pages/fakta-hvor-meget-kan-jeg-overfoere-med-mobilepay.aspx  Be sure to test with reasonable amounts and only run a limited number of transactions.


General - Sign Up & Get Started

Merchant flow 

  • The merchant signs up for MobilePay Subscriptions or Invoice in a few simple steps on the MobilePay Self-service portal https://admin.mobilepay.dk/ 
  • Once the merchant has completed the order (KYC / Legimitation etc), our onboarding team at erhverv@mobilepay.dk will verify your information and activate the Subscriptions and/or Invoice product.
  • If the merchant is already a MobilePay customer, they just need to select the product.   

MobilePay Portal




When buyers and customers see the MobilePay button or logo on our website or pdf, then they know they can securily pay with using any of the MobilePay supported methods. It is therefore important that you use the right MobilePay buttons and logo's. 

Button Manager

How it works: 

You can embed our buttons directly in your code and ensure that you are always updated with the right button. You can embed our buttons directly in your code and ensure that you are always updated with the right images, styling effects and function calls: 

Embed buttons

If you are managing a large number og MobilePay integrations and buttons, consider using the embedded button function.


Visit our ressource page to find buttons. Just choose Asset type: "Button: Standard", "Button: Pay with" or "Button: Checkout":


Visit our ressource page to find logo and icons. Just choose Asset type: "Icon and name" or "Icon": 
MobilePay ressources
Download Logo Zip 
You'll find all of the logo's on MobilePay's website here 

You can add further team members to access your developer organisation and help manage your integration. Each team member can have different privileges that restrict the information they can see or actions they can take.

Contact developer@mobilepay.dk to add new members to your developer organisation (remember to include the e-mail address on the new member).

All the available end points' descriptions, error responses, request parameters, and code examples are listed in the below GitHub links:

Check'em out!

You'll also find the API reference within the specific Products here 

Note that this API might change in the future based on the feedback. Also, the above mentioned documentation discusses the latest version of the APIs. If you have feedback to the documentation, please contact developer@mobilepay.dk 

Create an app

  1. Log-in. In sandbox the url is https://sandbox-developer.mobilepay.dk and for production it is https://developer.mobilepay.dk 
  2. Create App: To register an app, click on your e-mail in the top (after you have logged in) and press the My Apps page, where you click Create App. 

Once you have provided an application name, description, etc. MobilePay generates a set of credentials for your app. You will be shown your application client_id and client secret.

Make a note of your client secret because it is only displayed once. You must supply the client secret when you call an API that requires you to identify your app. This is done by using both client ID and client secret.

The REST API support Denmark and Finland. 

You need to have ordered the product here in order to be invited. You will not be able to create an app and access the REST API to make test calls to them, unless you have been invited.

  1. Firstly, you will be contacted by MobilePay Business who will handle the product onboarding.
  2. Secondly, the DeveloperSupport team will handle your technical onboarding. 
  3. After having received the confirmation email and completed configuring your account, you will be able to login and start using our MobilePay test environment.

Once the above is handled, then you will receive an invite to MobilePay Sandbox Developer Portal, where you must create an user. The Developer Portal is primarily used by the technical contact. If there are more developers, who should be invited to the Developer Portal, please let us know and forward us their e-mail address, and then we will invite them.

The first steps

1. Log-in: 

In sandbox the URL is https://sandbox-developer.mobilepay.dk and for production the URL is https://developer.mobilepay.dk

Credentials are created using the mail invites received from the MobilePay Developer Support.

2. Create an app:

From the developer portal, click on your e-mail in the top and choose ”My Apps” at the top of the page. Click the create new app button.  

NOTE: You can create more than 1 app, but it is up to you and your implementation. How you handle the data internally in your organisation is up to you, and not MobilePay. If you decide to create more apps, then you also need to manage the data. We recommend that you keep it simple and stick to one app.

We have one example of a merchant that has 3 apps, but as the merchant is a Publishing company, they are providing 3 different magazines. 3 different magazines means 3 different services that the customer can buy. Therefore, they chose to have 3 apps. Otherwise, all other merchants have 1 app. 

Once you have provided an application name, description, etc. the system automatically generates a set of client-secret and clientSecret for your app. You will be shown your application client_id and client_secret

Make a note of your client_secret because it is only displayed once. You must supply the credentials when you call an API that requires you to identify your app by using a Client ID and Client secret.  

For example, If you have two apps, then you need to manage the Client-secret and ClientSecret for 2 different apps. 

3. Subscribe to API's

Now that you’ve registered your app, you need to subscribe to Invoice and/or Subscriptions API's, depending on your need. 

  • Invoice
  • Invoice user simulation
  • Subscriptions
  • Subscriptions User Simulation

Is it possible to test an API before signing up to a plan?

It is possible to test an API from this Developer Portal.

When looking at the details of an API you will see a table of the operations contained in the API. This will show what method they are (GET, POST, PUT, DELETE, PATCH, HEAD or OPTIONS) and what path the Resource uses.

If you click on the Resource you will see more information about it, what parameters it might take, what it returns, what possible return codes it might use and what they mean.

There is also a 'Try' button which enables you to try the Resource out direct from the Developer Portal.

If the API requires a client ID or a client secret for identification then you can specify these at the top of the 'Try' section.

The plan I subscribed to has a limited amount of calls per API. How can I monitor my usage against that?

The numbers of requests, for different APIs, that your application has made are shown on your application page.

Click 'Apps' in the main menu and then click on your application. Under 'Subscribed Plans' you will see all plans your application is subscribed to. 

For each API contained in that plan you can see the usage compared to the rate limit of the plan.

I just want to use an API? What are plans?

A plan is collection of API resources or subsets of resources from one or more API. A plan can contain a mixture of HTTP GET, PUT, POST, and DELETE verbs from different APIs or it can contain all the GET verbs from various APIs. A plan can have a common rate limit for all the resources or each resource can have a different rate limit. Rate limits specify how many requests an application is allowed to make during a specified time interval.

Use this Developer Portal to browse the different plans that are available to you and select a plan that is most suitable for your requirements. Some plans have restricted access that you must request access to use. When you submit your request, the organization is notified, the API administrator assesses your request and they might contact you for more details. Other plans are available to use straight away.

Integrator - Glossary

merchant_vat is used to identify which merchant that should be given consent to if a user has multiple merchants assigned. You should include it, as it is a practical way to manage merchants going through the OIDC flow, which is also a more scalable solution, as the your merchant customer base grows. 

When you include the VAT, it is even easier for you to identify the merchant, as the VAT numer is then directly mapped to the access_token. Therefore, tracking is made easier. 


  • You should include the VAT if you are an integrator managing the MobilePay API solution on behalf of others.
  • If you have more than one VAT number that you are managing the MobilePay API solution for.

403 Forbidden

  • As an integrator, you will be making API calls on behalf of a merchant. If you are getting 403 forbidden, The server understood the request, but will not fulfill it due to client-related issues. It is because you did not include the merchant_vat in the authorize request. The server understood the request, but will not fulfill it due to client-related issues.



You should send it as an extra URL parameter (authorize?merchant_vat=DK12345678).

You can find the information by extracting it from the access_token 

The extension methods support three different scenarios, to get the merchant_id.

  1. You have a JWE or JWS in 'Compact Serialization Format'.
  2. You have a System.Security.Claims. ClaimsPrinciple 

  3. You have a System.Security.Claims. ClaimsIdentity 


Issuer is https://api.mobilepay.dk/merchant-authentication-openidconnect

There is a possibilty that there are issues with getting the url to be correct. 

Most OIDC libraries have a possibility to turn of the issuer validation. You can try that. 

Right now, MobilePay cannot change the incorrect Issuer url, because that would entail that MobilePay risks that some integrators validate with their hardcoded values, which results in it failing for them. 


  • ReUse: the refresh token handle will stay the same when refreshing tokens
  • OneTime: the refresh token handle will be updated when refreshing tokens


When an access token has been issued, then you can use it until expiry. So if you use refresh token to obtain a new access token, where the lifetime overlaps, then they can be used at the same time. The above fact is not related to OneTime or ReUse of refresh tokens.

Proof Key for Code Exchange

See more here: https://developer.mobilepay.dk/node/1354

A method that was used to derive code challenge.

As soon as you have gotten a refresh token, then you can keep on refreshing the access token with the same refresh token. Every time you use refresh token, then the "sliding lifetime" (which is 13 months) re-set. The edge case of using ReUse is if there is no API activity for over 13. months, which is highly unlikely. In this case, after 13 months, the refresh token would not work, and the merchant would need to log-on to https://admin.mobilepay.dk

ReUse will alleviate the client from having to update its stored refresh token and allow it to use the same one with each request.


  • Ensure that the api activity matches the refresh token expiration, which is 13 months. Alternatively, you can refresh the token with one week interval. 
  • Your refresh token should not be exposed, so if you have suspicion about it being exposed, please contact developer@mobilepay.dk instantly and then we will ensure that the token will be revoked. 

 Best Practice

  • Please read the best practice for token management on our Developer Portal here

The discovery endpoint can be used to retrieve metadata about theIdentityServer - it returns information like the issuer name, key material, supported scopes etc. See the spec for more details.

The discovery endpoint is available via /.well-known/openid-configuration relative to the base address, e.g.:



You can use the IdentityModel client library to programmatically access the discovery endpoint from .NET code. 

var client = new HttpClient();

var discoveryDocumentRequest = new DiscoveryDocumentRequest


   Address = "https://api.sandbox.mobilepay.dk/merchant-authentication-openidconnect/.well-known/openid-configuration/",

   Policy = new DiscoveryPolicy


       ValidateIssuerName = false,

       ValidateEndpoints = false




var disco = await client.GetDiscoveryDocumentAsync(discoveryDocumentRequest);

For more information check the IdentityModel docs.

JWT tokens are serialized using Base64 URL encoding.

IdentityModel includes the Base64Url class to help with encoding/decoding:

var text = "hello";
var b64url = Base64Url.Encode(text);

text = Base64Url.Decode(b64url);


ASP.NET Core has built-in support via WebEncoders.Base64UrlEncode and WebEncoders.Base64UrlDecode.

ui_locales gives a hint about the desired display language of the login UI

Integrators will need to supply the “ui_locales” parameter when creating the authorization URL that starts the consent flow, as described in the specification here https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest.

To enable Finnish language, the “ui_locales” must have the value “fi-FI”.

Using the ConsoleClientExample code that used is availble GitHub, the first part of the code would look like this:

var client = new OidcClient(OidcClientHelpers.ConfigureOidcClient(RedirectUri));


var extraParameters = new Dictionary<string, string>


    {"ui_locales", "fi-FI"}



var state = await client.PrepareLoginAsync(extraParameters);


The above is simply using IdentityModel, so it also applicable to other implementations in C#.


The Sandbox MobilePay Portal in Finland is 


The Production MobilePay Portal in Finland is 


Response Mode (Response_mode) is an Authorization Request parameter that informs the Authorization Server of the mechanism to be used for returning Authorization Response parameters from the Authorization_endpoint.

In the /authorize request you need to follow our docs here

Each value for response_mode delivers different behavior:

  • form_post sends the token response as a form post instead of a fragment encoded redirect . In this mode, Authorization Response parameters are encoded as HTML form values that are auto-submitted in the User Agent, and thus are transmitted via the HTTP POST method to the Client, with the result parameters being encoded in the body using the application/x-www-form-urlencoded format. The action attribute of the form MUST be the Client's Redirection URI. The method of the form attribute MUST be POST
  • fragment - Parameters are encoded in the URL fragment added to the redirect_uri when redirecting back to the client. For web applications, we recommend using response_mode=form_post, to ensure the most secure transfer of tokens to your application.


Several merchants and integrator have reported their OpenID processes not to redirect to the correct URL, and for these it has been identified that form_post mitigates this issue.

If you are able to exchange codes and tokens using fragment that is also ok. MobilePay supports both.

Response Type value that determines the authorization processing flow to be used, including what parameters are returned from the endpoints used.

For Hybrid Flow, it is code id_token

response_type is code, indicating that we are using the authorization code grant type.


production https://admin.mobilepay.dk/account/connect/authorize
sandbox: https://sandprod-admin.mobilepay.dk/account/connect/authorize

OpenID configuration endpoints


Find the configuration links below:

Environment Links
Sandbox Denmark https://sandprod-admin.mobilepay.dk/account/.well-known/openid-configuration
Finland https://sandprod-admin.mobilepay.fi/account/.well-known/openid-configuration
Production Denmark https://admin.mobilepay.dk/account/.well-known/openid-configuration 
Finland https://admin.mobilepay.fi/account/.well-known/openid-configuration

The token endpoint is used to programmatically request tokens. 

You can use the IdentityModel client library to programmatically access the token endpoint from .NET code. For more information check the IdentityModel docs.

Token Endpoint 


Find the configuration links below:

Environment Links
Sandbox Denmark https://sandprod-admin.mobilepay.dk/account/.well-known/openid-configuration
Finland https://sandprod-admin.mobilepay.fi/account/.well-known/openid-configuration
Production Denmark https://admin.mobilepay.dk/account/.well-known/openid-configuration 
Finland https://admin.mobilepay.fi/account/.well-known/openid-configuration

ID Token JSON Web Token (JWT) [JWT] that contains Claims about the Authentication event. An identity token represents the outcome of an authentication process.

The ID Token consists of three period-separated, Base64 URL-encoded JSON segments: a header, the payload, and the signature.

The ID tokens are in JSON Web Token (JWT) format, the specification for which can be found here: https://tools.ietf.org/html/rfc7519. They are signed using private JSON Web Keys (JWK), the specification for which you can find here: https://tools.ietf.org/html/rfc7517.


What to Check When Validating an ID Token 

The high-level overview of validating an ID token looks like this:

  1. Retrieve and parse your JSON Web Keys (JWK), which should be checked periodically and cached by your application.
  2. Decode the ID token, which is in JSON Web Token format
  3. Verify the signature used to sign the ID token
    1. You verify the Access or ID token's signature by matching the key that was used to sign in with one of the keys that you retrieved from your Authorization Server's JWK endpoint. Specifically, each public key is identified by a kid attribute, which corresponds with the kid claim in the Access or ID token header. If the kid claim doesn't match, it's possible that the signing keys have changed. Check the jwks_uri value in the Authorization Server metadata and try retrieving the keys again from MobilePay.
  4. Verify the claims found inside the ID token
    1. The iss (issuer) claim matches the identifier of your MobilePay Authorization Server.
    2. The aud (audience) claim should match the Client ID that you used to request the ID Token. 
    3. The iat (issued at time) claim indicates when this ID token was issued, expressed in Unix time.
    4. The exp (expiry time) claim is the time at which this token will expire., expressed in Unix time.
    5. The nonce claim value should match whatever was passed when you requested the ID token.

String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.

Code_challenge: A challenge derived from the code_verifier that is sent in the authorization request, to be verified against later. 

If the client is capable of using "S256" it must use "S256" as "S256" is mandatory to implement on the server. 

  • Code_verifier: A cryptographically random string that is used to correlate the authorization request to the token request.

With regards to code_verifier, you should use the value, that you used when creating the code_challenge in the /authorize ? call. 

By using the value, that you used when creating the code_challenge, we have a way for MobilePay to verify the call. It should match. You execute the Authorization call once, and you also make the code_challenge once with one code_verifier. But you need to save your code_verifier so you can use it, every time you utilize your refresh token. This means that you’ll not need to go through the Authorize call again, but you simply need to utilize the code_verifier from the original authorization call.

CodeVerifierMinLength = 43
CodeVerifierMaxLength = 128

After checking for all required parameters, and authenticating the client if the client was issued a secret, the authorization server can continue verifying the other parts of the request.

The server then checks if the authorization code is valid, and has not expired. The service must then verify that the authorization code provided in the request was issued to the client identified. Lastly, the service must ensure the redirect URI parameter present matches the redirect URI that was used to request the authorization code.

If everything checks out, the service can generate an access token and respond.


The Authorization Code grant type is used by confidential and public clients to exchange an authorization code for an access token.

After the user returns to the client via the redirect URL, the application will get the authorization code from the URL and use it to request an access token.

It is recommended that all clients use the PKCE extension with this flow as well to provide better security.


The token endpoint will get a request to exchange an authorization code for an access token. This request will contain a redirect URL as well as the authorization code. As an added measure of security, the server verifies that the redirect URL in this request matches exactly the redirect URL that was included in the initial authorization request for this authorization code.

The authorization server is what the user interacts with when an application is requesting access to their account. This is the server that displays the OAuth prompt, and where the user approves or denies the access request.  The authorization server is also responsible for granting access token after the user authorizes the application.

OAuth 2.0 is the modern standard for securing access to APIs. You can try out the OAuth 2.0 Playground here  which will help you understand the OAuth authorization flows, and show each step of the process of obtaining an access token. 

The examples walk through the various OAuth flows by interacting with a real OAuth 2.0 authorization server. 


What is it? 

A type of access token that lets you complete an action on behalf of a resource owner. The MobilePay authorization server issues access tokens called bearer tokens, that you use for authorization when you make REST API requests. A bearer token enables you to complete actions on behalf of, and with the approval of, the resource owner. 

How do I use it ? 

  • You should include the bearer token in the API requests in the Authorization header with the Bearer authentication scheme. 
  • Access tokens are also known as bearer tokens.
  • Bearer token format (C#): request.AddHeader("authorization", "Bearer <access_token>");


  1. What is it? An access token is the string used when making authenticated requests to the API. The token represents that the user has authorized a third-party application to access that user’s account. Access tokens (which aren't always JWTs) are used to inform an API that the bearer of the token has been authorized to access the API and perform a predetermined set of actions (specified by the scopes granted).  
  2. What do you use it for? The client uses an access token to make authenticated requests on behalf of the end user. When an access token expires, attempts to use it fail, and the app must obtain a new access token. 
  3. How long is it valid? It is valid for 5 minutes, so if the error message is saying its invalid – perhaps it simply expired. You will use the access token when passing it in the header. Access Token lifetimes are kept to very short lifetimes. When an access token has been issued, it can be used until it expires. 
  4. How long is it? 1000-1200 chars. We recommend that you plan for your application stack to handle tokens with length of at least 1200 characters in order to accommodate current and any future expansion plans. 
  5. What does it contain? It contains a header, payload, and signature. A resource server can authorize the client to access particular resources based on the scopes and claims in the access token.

When an access token has been issued, you can use it until expiry. So if you use refresh token to obtain a new access token, where the lifetime overlaps, then both tokens can be used at the same time. The above fact is not related to OneTime or ReUse of refresh tokens.

A client is the one, that requests tokens from Identity Server. The client must be registered with the Provider. The Provider is the one that issues tokens to clients. The client-id is usually the company name in small letters. You receive the client-id from developer@mobilepay.dk in a closed zip file. 

Authorization Request uses extension parameters and scopes defined by OpenID Connect to request that the End-User be authenticated by the Authorization Server, which is an OpenID Connect Provider, to the Client, which is an OpenID Connect Relying Party.

At this point, the authorization server validates the redirect URL to ensure the URL in the request matches one of the URLs for the application, that MobilePay has registered. The request will also have a client_id parameter, so the service should look up the redirect URLs based on that. 



We require the OAuth 2.0 state parameter on all requests to the /authorize endpoint in order to prevent cross-site request forgery (CSRF). he OAuth 2.0 specification requires that clients protect their redirect URIs against CSRF by sending a value in the authorize request that binds the request to the user-agent's authenticated state. Using the state parameter is also a countermeasure to several other known attacks as outlined in OAuth 2.0 Threat Model and Security Considerations


The state can be an arbitrary value. In the future , the state parameter is used to prevent Cross-Site Request Forgery (CSRF) attacks. In addition to this, because the redirect_uri parameter is fixed in the production version, the state can be used to distinguish users.

The same value will be returned to the [REDIRECT_URI] as a state parameter. For example: if you included parameter state=4cac8f43 in the authorization URI, when the user is redirected to [REDIRECT_URI], the URL would contain that same value in astate parameter. The value of state should be unique for each request.

In terms of differentiating merchant, you can do so by state. In the first call, the authorization call, you set a state. MobilePay then returns this state, when you obtain the authorization_code. This way, you can differentiate, if you have more merchants working on the Consent process. Afterwards, it is your responsibility to manage, which tokens belong to which merchants. This is solely a security aspect, that we do not enclose information about this, when you get the refresh_token. But this is also a response for a call, that you initialised yourself, and the response comes instantly. This is why there shouldn't be any confusion. 

Identity Server

Identity server will echo back the state value on the token response, this is for round tripping state between client and provider, correlating request and response and CSRF/replay protection. 


An authorization code is an intermediate token used in the server-side app flow. The authorization code grant is used when an application exchanges an authorization code for an access token. After the user returns to the application via the redirect URL, the application will get the authorization code from the URL and use it to request an access token. This request will be made to the token endpoint. The Authorization Code is always returned when using the Hybrid Flow. 

  • How do I get it? You receive the Authorization Code via a round trip to the MobilePay Authorization server. 
  • What do I use it for? You request a response using the Authorization Code at the Token Endpoint 
  • For how long is it valid? Code has a lifetime of 5 minutes and can only be used once. 

Merchant only needs to give consent once, unless you lose the Authorization Code, the Authorization Code expires, or you lose the access token.Please ensure you do not use the Authorization code more than once, and that it is used within 5 minutes.

A Client makes a Token Request by presenting its Authorization Grant (in the form of an Authorization Code) to the Token Endpoint using the grant_type value authorization_code

 As long as you’ve obtained the access token and refresh token, you do not need to think about Authorization Code. Especially since you are only required to deliver the access token in the API request. You do not deliver the Authorization Code in the API request. 


A token used to obtain a renewed access token without having to re-authenticate the user.


  • The grant_type parameter should always have a value of refresh_token in this flow and the value of the refresh_token parameter should be the actual refresh token obtained by the client after some other flow.

Requesting a token using the refresh_token Grant Type

The RequestRefreshToken extension method has convenience properties for the refresh_token grant type:

var response = await _client.RequestRefreshTokenAsync(new RefreshTokenRequest
    Address = TokenEndpoint,

    ClientId = "client",
    ClientSecret = "secret",

    RefreshToken = "xyz"

 In case you get an error message when going through the OpenID Flow the checklist below might be beneficial for you. The checklist assumes that you have read the documentation and that you've followed our recommendation on how to send the requests. If you haven't done so, please read it here 

You need to check the following, to ensure you will successfully implement OpenID Connect

Number Checklist

Description of solution

1 Is the  redirect_uri whitelisted?

Have you used a redirect_uri that has been whitelisted at MobilePay? You can only use the redirect_uri that has been whitelisted. If it has not been whitelisted, you should write to developer@mobilepay.dk in order for it to be whitelisted.

You cannot use an redirect_uri that hasn’t been whitelisted by us. 


 Is the redirect_uri a https?

It should always be https (unless it is local host) otherwise you'll receive an error message



Do you use the same redirect_uri?


The URL’s need to be both on authorize https://sandprod-admin.mobilepay.dk/account/connect/authorize? and token requests  https://api.sandbox.mobilepay.dk/merchant-authentication-openidconnect/connect/token? 


Do you use the correct clientSecret and clientID


You should use the  clientID and ClientSecret from the zip file when getting/renewing access token

You should not use the x-ibm-client-id from the developer portal when doing your OpenID Connect requests. 

5 Do you use the correct scopes?

You should use the following for each product 

  • Invoice invoice transactionreporting openid offline_access 
  • Subscriptions subscriptions transactionreporting openid offline_access 
6 Is the Code Challenge correct?


 The code challenge must be within these requirements:
  • CodeChallengeMinLength = 43
  • CodeChallengeMaxLength = 128

You can see more about the code challenge here

7.  Do you use the code within 5 minutes? The code has a lifetime of 5 minutes and can only be used once.  Successive token requests with the same code will result in error and invalidation of previously accessed tokens.



...no luck? If that doesn't help you, please send us a report, as demonstrated here.


common errors:

invalid_client The specified client ID is invalid
invalid_grant The specified grant is invalid, expired, revoked, or doesn't match the redirect URI used in the authorization request
invalid_request The request is missing a necessary parameter or the parameter has an invalid value
invalid_scope The scopes list contains an invalid or unsupported value 
unsupported_response_type  The specified response type is invalid or unsupported 
unsupported_response_mode The specified response mode is invalid or unsupported. 


When we send authorization code, we use ("#") instead of URL as parameter ("?"). For example: https://localhost:8080/mobilepay-authorized#code=af9fb6334....

with regards to the specification, it should be a parameter: https://tools.ietf.org/html/rfc6749#section-4.1.2

The reason why we use "#" is because, we use identityserver, and it is their default set-up. Moreover, we do not implement the whole OpenId specification.You can easily configure it with a response_mode like this: 


form_post sends the token response as a form post instead of a fragment encoded redirect (optional)


Furthermore, it should also be more secure to have data as a fragment instead of query, because there is nobody that saves it and reads it.

Access token and refresh tokens are issued by a merchant, and so is per merchant. Therefore, if a single merchant (a publisher let us say) has multiple subscription providers (different newspapers), you can use the same token for all of them, but for a different merchant (another publisher) you would need another token. 

You need to use the access token when calling the API. And when the access token is expired, you use the refresh token to get a new set of tokens. 


The IT integrator can exchange their refresh token for a new pair of access token and refresh token.

  1. Get the access token and refresh_token by redirecting the merchant to login URI and handling the response.
  2. IT-integrator stores the  access token somewhere, along with its validity (cache, in-memory dictionary or something else) and use it until it is valid. You can save the  access token  persistent. It depends on the implementation. 
  3. IT-integrator stores the refresh_token somewhere, where it would be persistent and secure.
    1. Note: that if a merchant revokes the consent, then there is a delay of 5 minutes where the integrator still can use the  access token until it expires.  refresh_token will not be able to be used, and this means that the integrator will not be able to obtain a new access_token 
  4. Once the  access_token expires, you use your stored  refresh_token  to get a new  access token  and  refresh_token  and repeat #3 and #4. It will contain  access_token ,  refresh_token and ExpiresIn property.
  5. If refresh token is no longer valid (that is, if you fail to refresh your tokens by using it before it expires) – you need to go back to step #1

If you’re using the same .NET library that’s used in our sample solution for interacting with OpenID Connect flow, then you can use OidcClient.RefreshTokenAsync() method to make the exchange. Also, the LoginResult class, coming back from OidcClient.ProcessResponseAsync() has a property called AccessTokenExpiration, which tells you how long the access token is valid, so that the IT-integrator can know, when it’s time to refresh the access token, without making a call to MobilePay service and receiving 401.


  • What is it?
    • It specifies the allowed redirect_uri to return tokens or authorization codes to. Learn more about the /authorize request here.
    • The best way to ensure the user will only be directed to appropriate locations is to require, that you to register one or more redirect_uriYou need to provide your own redirect_uri and send it to developer@mobilepay.dk so it can be whitelisted. 
  • Why should it be whitelisted at MobilePay?
    • MobilePay will only redirect users to a registered redirect_uri, in order to prevent redirection attacks where an authorization code or access token can be obtained by an attacker. MobilePay allows you to register multiple redirect_uri.
  • How long does it take to have it whitelisted?
    •  We will whitelist is as soon as we process your email request. Send the redirect_uri to developer@mobilepay.dk and we will confirm once it has been whitelisted.
  • What format should it have?
    • https:
      • In order to be secure, the redirect_uri must be an https endpoint to prevent tokens from being intercepted during the authorization process. If your redirect_uri is not https, then an attacker may be able to intercept the authorization code and use it to hijack a session.
      • All redirect_uri should be HTTPS 
    • Dynamic:
      • They cannot be dynamic. Here is what says in the OpenID Connect specification: Redirection URI to which the response will be sent. This URI must exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, 
  • Debugging - redirect_uri
    • If you get an invalid Redirect error, please ensure that you've used the redirect_uri, that has been whitelisted at MobilePay.  
    • Remember that you need to contact developer@mobilepay.dk when you need to have registered redirect URI's for both sandbox and production. 


According to the specification of OAuth 2.0 (RFC 6749), a client ID is required when you make an authorization request to an authorization server. Client ID and Client Secret for Authorization server will be provided in a password protected zip sent by developer@mobilepay.dk.

We need to know your mobile phone number, as we will send you the password for the zip in a text message.

  • The x-IBM client ID and secret should be used in the headers of all HTTP requests. For example when calling GET /api/merchants/me
  • The OTHER client ID/secret pair from the zip file, should be used, when during the OpenID flow (when getting/renewing access token), for example in /authorize and /token calls.

Please do not confuse the information from the zip file with the 'x-IBM client' credentials. The credentials that are sent via zip is meant for the OpenID Connect flow, and not the specific API calls

MobilePay supports different scopes.   

When making the initial authorization request, your application can request multiple scopes as a space or comma separated list, e.g.

The full list of possible scopes

subscriptions invoice openid transactionreporting merchantpayments webhooks offline_access


openid invoice transactionreporting offline_access
openid subscriptions transactionreporting offline_access
Transaction Reporting
openid transactionreporting offline_access
App Payments
openid merchantpayments webhooks offline_access

scope openid, means that the /token endpoint will return an ID token. For more information about scopes, see here. For details, refer to OpenID Connect Scopes

offline_access can only be requested in combination with a response_type that contains code.

If the response_type doesn't contain codeoffline_access is ignored.

transactionreporting can only be used in the production environment.

For more information about offline_access, see the OIDC spec.

Integrator authentication

The root/CA for chain validation can be downloaded her: https://danskeci.com/ci/transaction-banking/instructions/integration-ser... (Download the root certificate for Danske Bank Group (.zip))

Our TLS certificates are issued by GlobalSign CA’sand can be retrieved through a browser. Go to 
api.mobilepay.dk to retrieve it. 
You can validate the TLS connection, specific to api.mobilepay.dk, and optionally validate the certificate chain from the x5t to DanskeBank root
A base64 encoded certificate, signed by Danske Bank root, containing the public key used to verify the signature on the access token we issue
No, we expect our clients to have a dynamic setup which can handle certificate renewal automatically

The public certificate is updated every 2 years. The root/CA for chain validation can be downloaded her: https://danskeci.com/ci/transaction-banking/instructions/integration-ser... (Download the root certificate for Danske Bank Group (.zip))

Integrator General

Find the supported endpoints for sandbox here

Find the supported endpoints for production here


You will receive client-id and client-secret for sandbox and production environments. In both sandbox and production, you have the same client-id, but the client-secret is not the same in sandbox and in production. 

Once you've tested in sandbox environment, you'll receive client-id and client-secret for production in a password protected zip file. That is the only thing you need to go through the OpenID processes.

You will only need to administrate the following:

  • 1 client-secret for sandbox
  • 1 client-secret for production
  • The same client-id for both environments 

Obtaining tokens:

Once the access token expires, then you can use the refresh token to obtain a new access token. You can do this without merchant involvement. The refresh token expires after 13 months. 

You get a new refresh token through the following endpoint:


Once you have finished testing in sandbox and the verification, you and MobilePay's Developer Support team need to verify, that the set-up is also working in production. This is especially important with regards to using the right redirect URI's in production, and using the right credentials for OpenID Connect in production. You need to update all URLs and credentials to production values. 

Once you've done so, there are two possibilities, and you can choose the option, that fits you the best. 

Possibility - Test with your own customer. 

1.1 Possibility - Your customer has ordered a MobilePay API product 

If you have a customer ready for MobilePay Subscriptions, you have the possibility to arrange a "pilot" agreement with your customer. In this case, the merchant is already a MobilePay customer, and they just need to select the product. 

1.2 Your customer has not ordered a MobilePay API product

In case your customer doesn't have a MobilePay product ready, then your customer signs up for MobilePay Subscriptions or Invoice in a few simple steps on https://admin.mobilepay.dk/  and once the merchant has completed the order (KYC / Legimitation etc) we will verify the merchant information and activate the Subscriptions product. 

2. Test with your own account 

If you do not want to test with your customer, you have the possibility to order the API product yourself, so you have a profile in production. The benefit of testing in production with your own account is that you can demo the solution to your other customers, which is recommended. Furthermore, you are not dependent on your "pilot" customer. In this case, you'll be marked as an integrator, and will only pay for the transactions, and not the monthly fee of 499,-

OpenID Connect (OIDC) is a standard that provides a consistent set of OAuth 2.0 APIs for authentication across the Internet. 

OpenID Connect is considered to be the future because it has the most potential for modern applications. It was built for mobile application scenarios right from the start and is designed to be API friendly.



Theoretically, it is possible to enable sign-on/consent, but it is not recommended from the user security's perspective. 

If the sign-on is embedded on a website, then there is nothing that prevents the website from snatching the credentials. It is recommended that the sign-on flow is always opened in a new tab with a URL that you trust. In other words, MobilePay recommends the user to refrain from entering their credentials in an embedded web view, and always make sure that you enter a URL, that is separate, and that belongs to a website, that has your credentials (MobilePay in this case. 

For the same reson, MobilePay doesn't have experience with implementing an embedded sign-on, so we cannot help with it. 

The only thing common to this solution is the security aspect, OpenID Connect, so you would be able to share the access token and refresh token, and nothing else. It should be seen as two different products that share the same authentication process, which is OpenID Connect.

MobilePay has chosen to use Code Challenge, since it removes potential attack options. An intercepted code is unusable in itself, but the problem really lies in how "easy" it is to get a cliendID + ClientSecret valid for the Api Gateway. That depends on a hackers ability to decode either the stored client in the MobilePay app or any other 3rd party app. In other words, we cannot rely on it to secure a specific user credentials. Since there is no coupling between the code and the api-connect client, any MobilePay client will probably do. However, by using PKCE, MobilePay solves that problem.

PKCE / Code Challenge

MobilePay supports the Proof Key for Code Exchange protocol to make the flow more secure. A unique code verifier is created for every authorization request, and its transformed value, called "code_challenge", is sent to the authorization server to obtain the authorization code. 

Example: you can find it in the C# example. Note that it is hidden in the framework.  A line calls a identitymodel feature which automatically uses PKCE. Code challenge is also referred to as the code that you generated, and made cryptographically secure and sent to us in ./authorize endpoint property code challenge. 


  • code verifier: A cryptographically random string that is used to correlate the authorization request to the token request.
  • code challenge: A challenge derived from the code verifier that is sent in the authorization request, to be verified against later.
private string CreateCodeChallenge()
    _codeVerifier = RandomNumberGenerator.CreateUniqueId();
    var sha256 = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithm.Sha256);
    var challengeBuffer = sha256.HashData(
    byte[] challengeBytes;
    CryptographicBuffer.CopyToByteArray(challengeBuffer, out challengeBytes);
    return Base64Url.Encode(challengeBytes);

 Regarding code_challenge. Here is how Identity Server does validation: 

  • var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier);
  • var hashedBytes = codeVerifierBytes.Sha256();
  • var transformedCodeVerifier = Base64Url.Encode(hashedBytes);
  • return TimeConstantComparer.IsEqual(transformedCodeVerifier.Sha256(), codeChallenge);

If you get an error that the code challenge is either too short or too long, please update the value of code_challenge to meet the requirements and try again. Regarding code_verifier, it has the length requirements as code challenge. 

  • CodeChallengeMinLength = 43
  • CodeChallengeMaxLength = 128

The method for calculating code_challenge base64urlencoder(Sha256(code_verifier)) when challenge method is S256. 

The characteristics of the Hybrid Flow is summarized in the following non-normative table, and the table is intended to give an overview 

Property Hybrid Flow
All tokens returned from the Authorization Endpoint no
All tokens returned from the Token Endpoint no
Tokens not revealed to User Agent no
Client can be authenticated yes
Refresh Token possible yes
Communication in one round trip no
Most communication server-to-server varies

It’s a combination of the authorization code and implicit code flows. You can spot it by looking at the response_type it must contain code and one or both of id_token and token:


The Hybrid Flow follows the following steps:

  1. Client prepares an Authentication Request containing the desired request parameters
  2. Client sends the request to the Authorization Server.
  3. Authorization Server Authenticates the End-User.
  4. Authorization Server obtains End-User Consent/Authorization.
  5. Authorization Server sends the End-User back to the Client with an Authorization Code 
  6. Client requests a response using the Authorization Code at the Token Endpoint
  7. Client receives a response that contains an ID Token and Access Token in the response body.
  8. Client validates the ID Token and retrieves the End-User's Subject Identifier.


This authentication flow is a combination of the implicit and authorization code flows. The identity token is transmitted via the browser channel and contains the signed protocol response along with other artifacts such as the authorization code. After successful validation of the response, the back channel is used to retrieve the access and refresh tokens.

Yes, you do need to implement handling of OpenId Connect. Here is a code sample if needed https://github.com/MobilePayDev/MobilePay-Invoice/tree/master/ClientExamples 

It is a common standard and links to official flow is in our documentation on a github: http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth

  1. You only need additional API calls. You will need to do few API calls to get Token and refresh Token.
  2. When you have the Token, you will use it for every request to the Subscriptions Integrator API or the Invoice API.
    1. You'll find the API here 

You don’t need additional services hosted. What you need is an additional endpoints in your service that will handle a redirect from our system with auth code after merchant grants access to your app. 


Parameter Type Description
InvoiceNumber     string     Required.   It will be used if PaymentReference is not filled.

 In DK Translation: fakturanummer. 

InvoiceNumber is used for reconciliation purposes. This is why when you use the call 

GET api/v1/merchants/{merchantId}/invoices/{invoiceId}

You will have returned in the response the InvoiceNumber. 


If you fill out the field PaymentReference, then the ID follows, that you’ve written as a  PaymentReferencefor the payment, if the merchant has chosen Instant Transfers. PaymentReference is not a required string, as it is completely up to the merchant to decide, the needed ID used to reconcile transactions with the bank.

For example, if the merchant wants to use their FIK-Creditor-ID for transactions, then you simply choose the reference number, which can be the merchant FIK Creditor ID. There are no special requirements for the merchant FIK creditor-ID to be able to use it for MobilePay Invoice.

If you do not fill out  PaymentReference, then it would be the input from the field  InvoiceNumber,  that will be the reference on the payment. InvoiceNumber is a required string. 

At least one InvoiceArticle is required.

You can see visual examples here.

We do not validate invoice articles against the TotalAmount and TotalVatAmount. Merchant can do mistakes and we will not notice.  It is used for preview, PDF generation, but not for validating data.





SMS to user before due date

SMS is sent  just for ignored (not accepted or rejected) invoices.

SMS is sent to the user one day prior the due date at 13.30 PM where the job sending the SMS runs

If the due date equals the current date and the invoice is received before 13:30 PM then the SMS is sent to the user on due date

If the due date equals the current date and the invoice is received after 13:30 PM then the the SMS is sent to the user one day after the due date

Hello, Remember that you have received a bill for payment. Find it under MobilePay Activities and check if it's paid. Regards MobilePay

Hej, Husk, at du har modtaget en regning til betaling. Find den under Aktiviteter i MobilePay og tjek, om den er betalt. Hilsen MobilePay

Hei, Muista, että olet saanut laskun maksusta. Etsi se MobilePay tapahtumavalikon alta ja tarkista, onko se maksettu. Terveisin MobilePay

SMS to user when payment failes

If the future payment can't be processed (card action needed, raise limit action needed) SMS is sent Error time +8,5 h.

If the future payment can't be processed (other action needed) SMS is sent 13:30.

You have placed a bill for payment today, which was not possible to complete. Find it under Activities in MobilePay to make sure it's paid. Regards MobilePay

Du har sat en regning til betaling i dag, som ikke var mulig at gennemføre. 

Find den under Aktiviteter i MobilePay så du kan sikre dig, at den bliver betalt.  

Hilsen MobilePay

Olet maksanut laskun tänään, mutta sitä ei ollut mahdollista veloittaa.

Etsi se MobilePayn tapahtumavalikosta varmistaaksesi, että se on maksettu.

Terveisin MobilePay

Invoice callbacks are sent using batches.

The job starts every 30 seconds.

Read more here.

Now you have learned how to send an InvoiceDirect and InvoiceLink. Understanding what happens in Invoice PaymentFlow helps provide the smoothest experience for both you and your users.  Read more here 

Regarding InvoiceDirect, then the Invoice won't be created if consumer (user) does not have the MobilePay app.

if it is an Invoice Link in that case there is a "toast message" a red prompt message on the top of the landing page

As you can read here, If you fill out the field PaymentReference, then the ID follows, that you’ve written as a reference for the payment. If you do not fill out  PaymentReference, then it would be the input from the field  InvoiceNumber,  that will be the reference on the payment.

The merchant chooses the transfer type to decide how often the merchant would like to receive the transactions on their bank account. There are two types of transfer types

  • Instant transfers. Transfers are executed for each payment automatically.
  • Daily transfers. Transfers are executed ones per day for all payments per day.


You can choose a reference or ID on the invoices that your merchant sends via MobilePay Invoice. It is possible to do reconciliation in several ways.

  1. You get the status on the invoice through the API. When the Invoice has status paid– then it means that the money has been transferred to the customer’s bank.
  2. The individual transactions will contain the same reference/the ID, that you have assigned, and that reference/ID will be returned through the API.
  3. The merchant logs-in to our MobilePay portal on https://admin.mobilepay.dk where you can export the transactions in a csv-file.
  4. Use the Transaction Reporting API.

For example, if the merchant wants to use their FIK-Creditor-ID for transactions, then you simply choose the reference number, which can be the merchant FIK Creditor ID. There are no special requirements for the merchant FIK creditor-ID to be able to use it for MobilePay Invoice.

Right now, we do not do cross border payments. This means that a Danish merchant cannot send an invoice to a Finnish person.

The merchant and integrator can cancel an invoice which has not yet been paid , rejected and has not expired. The cancelling will be executed asynchronously and the callback will be sent to you with status.

If the customer has chosen to pay at a later point, then the invoice can still be canceled by the merchant. The customer does not receive a notification. Changes will be visible in the MobilePay Activity List. The pending Invoice Payment will be changed to canceled. On payment date (if the user set the invoice to be paid at later point), MobilePay checks the status of the invoice. If it is canceled , then MobilePay ignores "Pay" command.

In order to receive callbacks about status changes for an invoice a callback URL must be specified first. But before setting your callback URL you must choose prefered authentication method which we will use for authenticating our requests when calling your callback URL. Currently we support Basic and ApiKey authentication methods:

PUT /api/v1/merchants/{merchantId}/auth/basic
PUT /api/v1/merchants/{merchantId}/auth/apikey

 Using ApiKey authentication method your provided API key will be simply added to Authorizationheader.

  • Callback 
    • The Invoice API has a callback function, so your system can be notified, when the invoice has been paid. More information about callbacks can be found here.
  • Status 
    • After an invoice is created, you use the invoice status to indicate where it is in the processing cycle.  The status property reflects the invoice's current state. More information about Invoice status can be found here

MerchantId is a unique identifier of a merchant in our system. After you retrieve an access token from OpenID flow use the following endpoint to retrieve your MerchantId.

GET /api/v1/merchants/me



Read more here

Afterwards you should get an invoice issuer 

GET /api/v1/merchants/{merchantId}/invoiceissuer


You can register for MobilePay Invoice here 

You'll find the Invoice validation here 

What is an Invoice Issuer? 

Invoice issuer represents merchant’s company information. Each invoice issuer contains its own address information, account data and logo. The merchant is the customer company and the Invoice Issuer is the actual service provider name under which they create invoices. Read more here 

How do we administrate MobilePay Invoice?

Before using MobilePay Invoices, the merchant must have at least one invoice issuer which can be created via MobilePay Portal Denmark or Finland

Do not confuse Invoice Issuer with merchant.  The merchant is the customer company and the Invoice Issuer is the actual service provider name under which they create invoices

GET /api/v1/merchants/{merchantId}/invoiceissuers


"Address":"Paradisæblevej 13",

What do I use MerchantID for?

MerchantId is a unique identifier of a merchant in our system. After you retrieve an access token from OpenID flow use the following endpoint to retrieve your MerchantId.

GET /api/v1/merchants/me



Once you have the MerchantId  you can then specify a invoice callback url. You will use MerchantId  in the endpoints towards the Invoice API. 

Method 1. Basic

Using basic All the REST callbacks will be sent to CallbackUrl and contain basic credentials in Authorization HTTP header:

Authorization: Basic [Base64 encoded username:password]

PUT /api/v1/merchants/{merchantId}/auth/basic
Method 2. ApiKey
PUT /api/v1/merchants/{merchantId}/auth/apikey

Using ApiKey authentication method your provided API key will be simply added to Authorization header.

For this flow, the full list of possible scopes is "invoice openid offline_access". Use "openid" and "offline_access" and "invoice"  

Guid is valid value for “CustomerCard” property.

Currently only this Guid will pass validation: dcdb5118-e94b-4d89-b86c-cf2021bb837d


In the documentation ConsumerName is a required string. It entails the full name of the MobilePay user. We validate it using Levenshtein distance in order to ignore minor spelling mistakes.  the Levenshtein distance between two words is the minimum number of single-character edits (insertions, deletions or substitutions) required to change one word into the other.

The edit distance: is the minimum edit distance between two strings. 

When you are sending the Invoice directly to MobilePay, using InvoiceDirect, then you need to know the customers name and mobilenumber. 

We recommend that the customer writes their real name as it is shown to other users in connection with transfers and requests. The customer can change their name in the App maximum two times in a month. The customer does this in the app in Settings --> Name and Address. 

Read more here 


Link expires:

  1. When invoice expires
  2. Invoice is rejected* (*When Invoice link with state Created, Visualized is rejected in the app it's not fully rejected but when Action request is unassigned.
  3. Invoice is accepted

You'll find all the request parameters for InvoiceLink Request Parameter here so you can see, which parameter is required and not required.


It is mandetory to update ReservationExpiryTimestamp if this changes. RedirectFromMobilePayUrl does not need to be updated but is an option you can use.

  • ReservationExpiryTimestamp: This update can be done after authorization update because the expireTimestamp is initially set on authorization update.  If the expiry of the reservation changes then you must update this ReservationExpiryTimestamp
  • RedirectFromMobilePayUrl : This update can be done after payment initiation and until authorization update or the user rejects the payment. RedirectFromMobilePayUrl  is set on payment initiation and will be used when authorization is successful or user rejects the payment.
    You can initiate the payment with a status-failure RedirectFromMobilePayUrl  and then update this to a status-success RedirectFromMobilePayUrl if the authorization is successful. 

The update is done using: PATCH /api/v1/payments/{paymentId}

If you have a partner that will be utulizing your integration it must be registered as a partner with MobilePay. To do so you must first create an app for this partner in the developer portal:

IMPORTANT: Please make a note of thr Client Secret as you will only see this once!  This must be supplied when calling the api. 

Then you contact us at developer@mobilepay.dk with the following information about your partner:

  • Official company name
  • VAT number
  • ClientId from the developer portal
  • Should the partner be invoiced directly by MobilePay or through you?

You partner will have its own set of credentials but should use your publicKeyId. 

If the 3Ds authentication fails then PSP must update the authorization attempt with "suceeded: false" to indicate that the authentication failed. 

As soon as PSP update the authorization attempt with “false” and a reasonCode that is not 1008 or 1009, then the web view will close. The user will then see the accept screen again and can try with a different card. This means that PSP do not need to redirect the user to the done3ds page as usual after a succesfull authentication. 

The user can then try with a new card which will result in a new callback to PSP, either a token og pan callback depending on the card.

On payment initiation you must defined allowed card types. This can be:
MC-DEBIT: MasterCard Debit
MC-CREDIT: MasterCard Credit
MTRO-DEBIT: Maestro Debit
ELEC-DEBIT: VISA Electron Debit
DANKORT: Dankort",

If user pays with Visa-Dankort, and allowed card types is set to VISA-DEBIT or VISA-CREDIT and not DANKORT, then we return VISA-DEBIT or VISA-CREDIT. If allowed card type is set to VISA-DEBIT, VISA-CREDIT and DANKORT we return Dankort.

If the webview is a custom webview that you have added yourself, you must open up for uri schemes calling out of the app as that is turned off by default.

If it is the webview of the Google Search App (iOS only) then we will always use the manual entering of phone no. as that webview does not accept external uri-scheme calls for now.

CorrelationId is a unique identifier value that is set as header for each API request: 

--header 'correlationid: REPLACE_THIS_VALUE'

The id serves as reference for the particular API request and makes API support more efficient. If you are having issue with an API request, please include the correlationId.

After a succesfull authorization you must update the payment to reflect the current status of the payment. This must be done synchronously to give the best user experience. It is not possible to do this in batches. 

It is possible to do multiple captures and refunds.

POST /api/v1/payments/{paymentId}/captures
POST /api/v1/payments/{paymentId}/cancels
POST /api/v1/payments/{paymentId}/refunds

When creating a merchant billingCurrency and countryCode is defined

countryCode: The country of the merchant. Will be used for invoicing between PSP and MobilePay if billingCurrency is not set.

billingCurrency: If the merchant is invoiced by the PSP in a currency of another country than given in countryCode you can give this invoice currency here. It will 'override' countryCode when we make your invoice. 

When initiating a payment currencyCode is defined

currencyCode: This defines the currency of the payment, and will not influence billing. 

Online - callbacks

Yes it can contain both billing and delivery address so you will only receive one callback. Which address it is will be indicated by these:

  • 'IsBillingAddress': true
  • 'IsDeliveryAddress': true

Please note that the same address can be both billing and delivery address and therefore the callback will only include one address.

TokenCallbackUrl and CardDataCallbackUrl can be the same endpoint ifthat suits your need the best. And if you want it to be the same endpoint, but still able to use different deserialization, you can put a parameter in the URI like this:


When using check out, you always receive adressCallback before cardDataCallback. The cardDataCallback will only be sent if the addressCallback is sent succesfully.

pspReferenceId is required upon payment initiation. It is used for support cases so that it is easier to find the relevant payment. Often PSP supporters does not have access to payment id (but we recommend that they do), and here the pspReferenceId can be used instead.  
The pspReferenceId is not returned in the cardDataCallback because you have the option to set callbackUrl per payment, which gives you great flexibility. It is possible to put whatever you need inside that url, even multiple identifiers (as long as it does not invalidate the Url).

A failed payment callback is sent to failedPaymentcallbackUrl when the payment ends unsuccesfull. This is either if the payment expires or if a fishing scenario have been attempted. This means that you do not receive a callback when the user rejects the payment in the app. The user have the option to start the MobilePay flow again as long as the payment has not expired. 

Online - merchant

For franchises you must create  each franchisor as individual merchants. You can also choose to setup the franchisee as partner if you want to, but that is not required from our side.

If a merchant operates in two countries you must create one merchant for each country and set the appropriate country code.  

We support all countries in EU/EEA. But only support the currencies: DKK, EUR,  SEK and NOK. 

Private users must be recidens of Denmark or Finland. 

Merchant name is defined on payment initiation and shown to the user in the MobilePay app. There is no limit to the lenght of name. The white box containing the name will just exxtend to fit the name. If the name becomes too long the box becomes scrollable.

On InitiatePayment you must define a merchantLogoUrl. If the merchant does not have a logo please use following url: https://no-logo.png

This results in standard merchant logo to be displayed in the MobilePay app.  

NOTE: All merchants should have their own logo to give the best user experience. Only use this as a temporary solution!


A merchant must be created through the API: POST to 


It cannot be created through an online account/dashboard/self-service portal.

Online - PublicKey

During the technical onboarding you will receive an email with details on how to get started. This will include a link to upload your publicKey. The link is valid for 30 days. If the link expires please contact us at developer@mobilepay.dk for at new link.

When we receive the publicKey we will register it and return a publicKeyId. 

The publicKey is used for encrypting card data and when you supply us with a publicKey we will return a publicKeyId. This publicKeyid must be supplied on each payment initiation. The id will be used to map your publicKey to your payments in order to encrypt the card data. 

As default we do not rotate publicKey. If you need to rotate the key we can support it. When you supply us with the first publicKey just let us know if you want to rotate it so we can agree on a schedule.

The publicKey does not have an experiation date and will not expire. Therefore you only needto supply us with one publicKey and it does not need to be replace unless you request it. 

It must be RSA encrypted. Our own example is created with 



An example of a key:

-----END PUBLIC KEY-----

Online - redirect

The redirectToMobilePayUrl is returned in the response body of payment initiation. The url is an universal link. This means that it can both open in a browser and open the MobilePay app if this is installed. 

Please note for iOS: When a user taps a universal link iOS also examines the user’s recent choices to determine whether to open the app or the url in the browser. For example if a user choose to open the url in the browser iOS continues to open the url in the browser until the user changes this setting.

Please note for Android: When the user is redirected to the url  the user will be prompted to choose whether to open the link in the browser or to open the MobilePay app. The user can then choose to save this setting and any future visits to the MobilePay url will follow this setting. 

In the following scenario you will always see two redirects by design:
  1. Complete a single device flow > The MobilePay app automatically opens redirectFromMobilePayURL in the browser.
  2. Now access the browser tab with the landing page that "popped" the app in step 1. > The tab will redirect to redirectFromMobilePayURL

The link to MobilePay landing page is received in response to payment initiation as: redirectToMobilePayUrl.

The language of the page is initialy defined by the countryCode of the merchant the payment is initiated on behalf of. Merchant countryCode is defined when creating a merchant with POST /api/v1/merchants 
This setting can be overulled by setting the customerLanguageCode on payment initiation. 
Code can be either DK or FI. If DK the laungage on landing page will be Danish. If FI the language on landing page will be Finnish.

The first time a user visits the landing page a functional cookie will be saved. This cookie defines the language of the page. Next time the user visits our landing page the language will be determined by cookie. Regardless of customerLanguageCode or countryCode. 


  1. Functional cookie in browser
  2. customerLanguageCode  on payment
  3. countryCode on merchant

User is redirect from redirectToMobilePayUrl to redirectFromMobilePayUrl when payment is either completed, failed or rejected. This means that user is not redirected right after they swipe in the MobilePay app, but when you either patch the authorization or payment is failed.



Online - Test

It is your responsibility to offer test options to your merchants as this is not possible for merchants to test directly with MobilePay.

You have two options:

  • Give them access to the sandbox API through your own interface and supply them your test merchant. You may request an extra test merchant for merchant test. You may supply this page to inform your merchants about the test app: https://sandbox-developer.mobilepay.dk/merchant_test Please note that it is your responsibility to support your merchants with the test app. If your merchants encounter any issue that you cannot resolve please contact us at developer@mobilepay.dk
  • Let your merchants perform test payments in production but mimic the authorization or simply mark the authorization as failed. 

During the technical onboarding you will receive a test user with our internal MobilePay test cards. If you wish to test with your own test card this is also possible. In order to register your test cards for your test user we must whitelist them.  To do so we only need the card number which you can send to developer@mobilepay.dk 

Please note that a test user can have a maximum of 6 cards registered. 

OpenID Connect library

Authenticating users properly is important to their and your safety and security, and using well-debugged code written by others is generally a best practice. 

    • Certified C#/NetStandard OpenID Connect Client Library for native mobile/desktop Applications. Get started here 
    • Javascript library 

Once you have followed this  guideline, you can now try to provoke errors to learn how the system behaves, e.g.

  • try to connect to IdentityServer when it is not running (unavailable)
  • try to use an invalid client id or secret to request the token
  • try to ask for an invalid scope during the token request
  • try to call the API when it is not running (unavailable)
  • don’t send the token to the API
  • configure the API to require a different scope than the one in the token

The access token expires after 5 minutes. Therefore, there is a delay, where the integrator still can use the access token until it expires. However, the refresh token will not be able to be used, and then the integrator will not be able to get a new access token. This is why we want to have short lived access tokens, as refresh tokens have a longer lifespan of 1 year, until they can be revoked. 

The consent is ‘only’ revoked when the person who has access to MobilePay Admin portal actively logs in, open product menu --> integration and clicks “x” to revoke consent. There appears a warning pop up, when doing so. It is just to illustrate that revoking consent is hardly done by ‘accident’.

It is a .NET standard helper library for claims-based identity, OAuth 2.0 and OpenID Connect.  It encapsulates the protocol interaction in an easy to use API.

It has the following high level features:

  • client libraries for standard OAuth 2.0 and OpenID Connect endpoints like authorize, token, discovery, introspection, revocation etc.
  • helpers for token management
  • constants for standard JWT claim types and protocol values
  • simplified API to access the X509 certificate store
  • misc helpers for base64 URL encoding, time constant string comparison and epoch time

What are the benefits? if you code in .NET then you do not need to think about code challenge, code verifiers etc. 


IdentityServer is an OpenID Connect provider - it implements the OpenID Connect and OAuth 2.0 protocols.

Different literature uses different terms for the same role - you probably also find security token service, identity provider, authorization server, IP-STS and more.

But they are in a nutshell all the same: a piece of software that issues security tokens to clients.

IdentityServer has a number of jobs and features - including:

  • protect your resources
  • authenticate users using a local account store or via an external identity provider
  • provide session management and single sign-on
  • manage and authenticate clients
  • issue identity and access tokens to clients
  • validate tokens

IdentityServer is built against ASP.NET Core 2 and runs on .NET Framework 4.6.1 (and higher) and .NET Core 2 (and higher).



There are many OpenID Connect certified libraries for different development platforms. You are going to integrate using a Standard Hybrid Flow, specified here

You can browse the libraries in a number of different languages that implement OpenID Connect here

Payment industry terms

Page token

JSON type




Unique page identifier when there are multiple pages of results. Can contain any base64 characters, including /, + and =.


Important: NextPageToken value can contain any base64 characters, including /, + and =. Be sure to properly escape the value (by using url encoding) when submitting request for the next page.


We are sending a token to you, that you need to encode, so you can use it in the following / next call.

You need to ensure that it is base64 encoded. 

Variable name Description Format Required Example
Type Type of transaction e.g. Payment, Payout, Fees, SentbackTransfer, Refund String 20  Yes Payment 
Variable name Description Format Required Example
Currency Transaction currency String 3  Yes  DKK, EUR  
Variable name Description Format Required
SenderCommment Message associated with payment from MobilePay user to payment receiver String 128 Yes
Name Type Required Detail
Amount Amount Yes Transaction amount. Positive for debit transactions, negative for credit transactions.
Name Type Required Detail
ReceiverAccount string Yes Account number where funds have been transferred to. IBAN or regular account number.
JSON type Description Examples
string Bank transfer reference number. For transfers made in Finland corresponds to 20 digit Finland bank transfer reference. Format can vary according to country's banking infrastructure regulations. The reference is considered unique for a duration of 1 year. "77060913004200000128"

Similar purpose as ExternalTransactionId but used for correlating transactions with bulk/group id from external (merchant/integrator) system.


API ExternalTransactionID
Invoice The individual transactions will contain the same PaymentReference, that you have assigned, and that PaymentReference, will be returned through the API.

Subscriptions external_id for recurring payments and one_off_payment.external_id for one-off payments will be used in bank statement in fields:

ExternalTransactionId is ID that could be provided by merchant / payment integrator when initiating payments. In general, it can be used for correlating transactions between MobilePay and external (merchant/integrator) system.


When using the Transaction Reporting API, you will be introduced to the term 'paymentPointId'. paymentPointId is a GUID assigned to payment point. 

MobilePay has different API products, and each API product has a payment point. The payment point is named differently.



API PaymentPointID Obtained
Subscriptions  SubscriptionsProviderID

You can call GET /api/merchants/me, which will return a list of all subscription providers, associated with that merchant.


Read more here 

Invoice  InvoiceIssuerID

You can call GET /api/v1/merchants/{merchantId}/invoiceissuer to get the ID


Read more here 


Save time: Matching incoming payments can be a time and resource expensive discipline. With the transaction reporting api, you can reconcile across MobilePay products using only one API. 

Work smarter: Automating repetitive and manual processes. Integrating the Transaction Reporting api means having reconciliation data delivered straight to merchant or integrators ERP or accounting system

Avoid manual errors and rework: Timely and correct reconciliation information, always at hand. If you use the Transaction Reporting api, you also avoid juggling files fro MobilePay portal and Online netbank on your computers. 





When the Subscriptions customer makes a one-off purchase or/and pays for their subscriptions, they can access the receipt in the activity list in the MobilePay app. This is useful for when/if the customer contacts the merchant regarding the payment. 

The screenshot below is an example. 

In the TransactionReporting api TransactionID is currently called PaymentTransactionId 


Payment Reference 

If you have one of our MobilePay products, then you can expect to see a Payment Reference in your bank account. Payment reference is a reference that is assigned to payment and is visible in bank account statement when payment is completed and received by your bank. It is usually used for tracking and verifying which payments were received to the bank account (e.g. transfers).

MobilePay specific reference:


PC =

Product code - Products need to identify the product, code is then put when generating the reference.

  • 01 = POS
  • 02 = MyShop
  • 03 = Subscriptions
  • 04 = Invoice
  • 05 = AppSwitch
  • 06 = Online
  • 07 = Marketplace
  • 08 = App payments
 RRRRRRRR   = External Payment Point ID (length 8)
  • (Myshop number, Pos LocationID....) - External Payment PointID will be sent in the payload from the product.The external payment point ID must be unique within the Merchant for the payment point. For Subscription and Invoice this will consist of 8 zeros (00000000).
JJJ  Running number (length 3)
DDMMYY  DDMMYY = Date (DDMMYY - lenght 6)

X = Check digit (length 1)

Example03000000000011602193 - which indicates Subscriptions payments received 16.02.2019. 

Account posting text is generated by MobilePay. It is the bank statement for the user. 

Structure is MobilePay provider name.


  • MobilePay Luxplus


  • MobilePay [Invoice Issuer name]


It will be visible on the customers bank account. 



The payload is the part of transmitted data that is the actual intended message. The payload excludes any headers or metadata sent solely to facilitate payload delivery.


The first four to six digits of a card representing the identification number of the issuing or acquiring bank.


Timestamp when transaction has been completed. Corresponds to url parameters "fromDateTimeOffset" and "toDateTimeOffset".

JSON type Description Examples
string All dates and times should be in UTC. The representation is an ISO 8601 24 character String "2007-04-05T24:00:17.154Z"


The authentication for PoS API v8 (and earlier) was API key and HMAC validation. This have been replaced by OAuth. This means that you do not need to exchange API keys with your merchants.

Instead you will receive security credentials through the technical onboarding. These you must use to retreive an authorization token through our Integrator Authentication API. Read more about authentication in our GitHub documentation. 

For documentation on how to create QR codes please visit the GitHub documentation

PoS onboarding

Merchants do not need to approve or inform us who their integrator is. As an integrator you are allowed to integrate on behalf of all our merchants a long as you are certified. You will only be able to access your own master data and therefore no other integrators can get access to your data for any merchant. 

No, a beacon must be unique and can only be registered for one posId. We also would not recommend using the same beacon for two pos' as it would only be possible to complete payments for one pos at a time, blocking the other pos.

Yes you can still use any existing whiteboxes you or your merchants have. They will work with both bluetooth and QR code. You register them by using the 15 digit unit id as beaconId when registering a posId POST /v10/pointofsales

We recommend that integrators retrieve this data through the API as described here. If needed merchants can export their store data from our self-service portal and send to their integrator. 

The data retrieved from the portal will include:

  • StoreId
  • Name
  • City
  • ZipCode
  • Street
  • MerchantLocationId
  • MerchantBrandId
  • BrandName
  • State

The data will be in a comma seperated Excel file: Example file

Example of the data:

Id Name City ZipCode Street MerchantLocationId MerchantBrandId BrandName State
d52f45d6-9af0-4885-8241-28e92289d2b3 TestStore29 City 1234 Street 45844 MPPOSSANDP MobilePay SandProd Test DK Activated

The merchant can export the file by clicking 'Eksporter butiksinfo'/'Lataa myymälätiedot' in the Point of Sale overview.



In POS v10 you no longer need to receive any information from MobilePay to get started calling on behalf of a merchant.
Based on a merchant VAT-number you can retrieve all needed information of a merchant, including storeId's and details of storeId.

Retreive storeId by calling GET/v10/stores with merchant VAT-number in header: x-mobilepay-merchant-vat-number 
Retrieve storeId details by calling GET/v10/stores{storeid} 
Example response:

 { "storeName": "Store 1",
  "storeId": "b3f69e80-f8dc-4d81-8f46-24a8fd8fbd9f",
  "storeStreet": "Example City",
  "storeZipCode": "1234",
  "storeCity": "Example City",
  "brandName": "The Brand",
  "merchantBrandId": "POSDK12345",
  "merchantLocationId": "10001"

POS v8 deprecated

If you wish to use QR codes you can order them here: Mobilepay.dk You will then receive MobilePay POS unit ids, which you can use to create QR codes. 

The correct format for creating the QR code is: mobilepaypos://pos?id=<posunitid>&source=qr 

Please be aware that it is all lowercase. The POS unit id is a 15 digit number (no letters). 

If you are using Windows 10, please follow below guide, to make the POS unit driver work. 

If a merchant have a loyalty agreement with MobilePay, this can be utilized through the POS API to recalculate payments/reservations based on the loyalty. To do this, payments/reservations must be initialised with loyalty-flow. Payment can be started with loaylty-flow before the user checks in, or after the user checks in. It can also be used in the reserve/capture-flow.

User checks-in before paymentStart

When payment is initiated after user has checked in, payment must be started as loyalty-flow (set customerTokenCalc to 0), so that payment can be recalculated after CustomerToken is received through the response. Updating the payment is done with a new PaymentStart where action is set to Update. After this, user can accept the payment.

  • User checks-in
  • Make PaymentStart:
    • Action: Start
    • CustomerTokenCalc: 0
  • Response:

    "CustomerToken": value,

  • Update payment with new PaymentStart:
    • Action: Update
    • Amount: insert updated amount
    • CustomerTokenCalc: 1

PaymentStart before user checks-in

Payment must be started as loyalty-flow (set CustomerTokenCalc to 0) to be able to recalculate after CustomerToken is received. Wait for user to check in and payment to change to status 60. After this, payment can be recalculated and user can accept the payment. 

  • Make PaymentStart:
    • Action: Start
    • CustomerTokenCalc: 0
  • User checks-in
  • Make GetPaymentStatus
    • "PaymentStatus": 60 (AwaitTokenRecalc)
    • "CustomerToken": value of token
  • Make new PaymentStart to recalculate payment
    • Action: update
    • Amount: insert updated amount
    • CustomerTokenCalc: 1


With reserve/capture flow, CustomerToken is received through ReservationStart or GetReservationStatus. After user have swiped to accept reservation, amount according to loyalty can be captured. 

System architecture
The following shows a system diagram of how a POS unit fits into the payment ecosystem
POS system arch

POS unit to Mobile App
The POS unit supports several communication interfaces with a mobile application and is currently based on BLE (Bluetooth Low Energy). A QR code and an embedded NFC tag are also available to provide the POS unit unique identifier and facilitate the commissioning of new POS units in the field.

State definition
The POS unit and smartphone go through a series of states to exchange information. The following describes each of the individual states

  • Check-In Process: To initiate a payment transaction the smartphone must establish a link with the POS unit in order to check-in. In order to check-in, the mobile phone scans for POS units in its vicinity and selects the closest one based on the strongest received signal strength indicator (RSSI).
  • Mobile POS Identifier Process: Once the smartphone and POS unit have established a link, the smartphone will query the unique mPOS identifier (a 15 digit number). This identifier is then validated against the database in Danske Bank, and once it has been validated, the check-in process is completed.

POS unit to POS Interface
The POS unit communicates with a POS by USB and interface with the host through a USB CDC (communication device class) interface. Windows driver is available here.

The POS unit uses an AT command serial interface (Hayes Command set).

PosUnit Connection
- Serial info:

  • Speed: 9600 Baud
  • Data bits: 8
  • Stop Bits: 1
  • Parity: None
  • Row Control: None

All commands are in uppercase and terminate with a carriage return (0x0D) control character. The following diagram shows the communication interface
AT command

AT command

Command Parameters Description Response
AT+BEACONID=? n/a Command to read mPOS 15 digit unique identifier XXXXXXXXXXXXXXX

The normal POS API is pull-based, requiring the POS system to pull updates from the API at regular intervals for processing. In addition to this functionality, the notification service offers a call-back functionality, which can notify a server endpoint, via a HTTP REST call, when a check-in or checkout occours.

The notification feature can be used for scenarios where you want to know if a user has checked in to the unit before issuing a payment. This can be useful for loyalty programmes, promotions or automatic discount calculations etc.

Endpoint scheme
Endpoints follow the standard HTTP URI scheme as specified in RFC7230. The MobilePay POS API will set a HTTP Authorization header based on the same HMAC authentication scheme as the MobilePay POS API uses. It is expected that the endpoint validates this if required. No other security mechanisms are supported

It is possible to register a notification endpoint on a location or for an entire merchant. Merchants can register up to one endpoint per location or merchant. It is currently not possible to register notification endpoint for the different POS systems.
To register endpoint(s) you send a mail to MobilePay Developer support mailbox (developer@mobilepay.dk) with the Merchantid and/or Locationid for each endpoint.
The same endpoint can be used for multiple Merchants/Locations. The endpoint(s) has to be functional when you send the registration mail.

When we receive the link to the end-point, we forward it to our security department. They will test and evaluate the endpoint. If approved the endpoint will be added to our database, and notifications will start to be sent to the endpoints. If not approved you will be notified with the reason for failing approval

First, the MobilePay POS API will check if a notification endpoint has been registered for the location in question and if not, check if a registration exists for the merchant in question:
If the MobilePay API finds a registered endpoint on the location, it will use this for notifications. Otherwise, it falls back to the one registered on the merchant level, if any.

A notification is sent when a customer checks in and checks out again during the payment flow:
Notification service flow

Expected return code
The MobilePay POS API will expect the notification endpoint to return HTTP 200 acknowledging that the notification has been received. The MobilePay POS API will try to resend the notification up to three times if a HTTP 200 response is not received. After this, no more delivery attempts for the notification in question will be made.

Message format
Notifications are carried out as a HTTP POST to the registered endpoint with this body payload:

“PoSId”: “a123456-b123-c123-d123-e12345678901”,
“AppId”:” ab3911f7-6a91-43c1-bb0f-4a73fe25773f”,
MerchantId String Merchant ID related to current PoS ID.
LocationId String Location ID related to current Merchant ID and PoS ID.
PoSId String Current Point of Sale ID (cash register/terminal).
PoSUnitId String PoSUnit Id identifies a PoSUnit - Box combining SmartBeacon / NFC-chip / QR-label / MobilePay terminal.
AppId String A unique identifier that helps identify the current app checking in or out. This identifier identifies the app, so if the customer has multiple apps/devices, each of these will have its own identifier.
Timestamp String The time and date for the notification formatted as an ISO 8601 date.
NotifyType String Either “Checkin” or “Checkout” at the moment.
CustomerToken String CustomerToken from merchant's Loyalty program, to be used to recalculate Payment Amount.

Message security
Each HTTP POST request has an HMAC-based authentication header set that can be validated on the receiving server. The authorization header is constructed in the same way as it is used in the MobilePay POS API.

The format of the HTTP authorization header is the following:
Authorization: {BASE64HMAC}˽{TimeStampUtc}.
The TimeStampUtc is the current UTC unix timestamp in seconds.
The BASE64HMAC is calculated as the following: Base64 (with padding) encoded HMAC SHA256:

HMAC = Base64(
            UTF8Bytes(“[request url]˽[content body]˽[TimeStampUtc]”),

You can integrate the Storebox API, to enable digital receipts for your customers. Please contact us, and we will supply you with the Storebox API documentation.

The general format is:

<base URL>/API/V08/<method>

The MobilePay PoS API is a REST interface over HTTPS using JSON format as input and output. The HTTP status codes 200, 400, 401 and 500 are used.
There are other HTTP status codes that must be handled by the PoS.

HTTP status code 200: Used in response to a successfully requests.
HTTP status code 400: Used in response to request dealing with other problems (used MerchantId is unknown etc.).
In the case of a 400 code the service will return JSON with the following format describing the error:
  "StatusText":"Invalid parameters"

HTTP status code 401: Used in response to unauthorized requests (as used HMAC could not be validated due to used APIKEY is invalid etc.).
HTTP status code 500: Used in response if an internal error at MobilePay has occurred (database server down etc.)

HTTPS communications are done via port 443, which is of benefit for those environments which block non-web Internet connections using a firewall.

A few notes:

  • Remember to use the content from the request.Content in your HTTP client. That is the content we see and use to calculate our HMAC header.
  • Remember NOT to add an extra "/" somewhere between the domain URL and /API/V07.
  • Remember to validate the JSON object before you send it.
  • Remember to save a log of all requests you send, so it is easier for you and us to find any errors.

// Create generic HMAC
string content = url + " " + jsonContent + " " + timeStampUtc;
var authorization = GetAuthorizationHeader (content, apiKey, timeStampUtc);
request.AddHeader("Authorization", authorization);
public string GetAuthorizationHeader(string hmacContent, string apiKey, string timeStampUtc)
    var base64Hmac = CalculateHmac(hmacContent, apiKey);
    var authorization =
                string.Format("{0} {1}",
    return authorization;
public static string CalculateHmac(string content, string key)
    var inputBytes = Encoding.UTF8.GetBytes(content);
    var keyBytes = Encoding.UTF8.GetBytes(key);
    using (var hmacSha256 = new HMACSHA256(keyBytes))
        var hashMessage = hmacSha256.ComputeHash(inputBytes);
        return Convert.ToBase64String(hashMessage);

 All HTTP MobilePay PoS method requests must comply following MobilePay authorization header with HMAC method:POS authorization

 This example is a calculation of the Authorization header based on the ApiKey "1234567890".

Resulting HTTP Authorization header:
Authorization: isGAb6zjnrOmHEj/d7ZE6VTEggY5zQqX7bnJ1/Y0gjc= 1413794400

Request URL: https://localhost:9003/API/V07/PaymentCancel
Content Body: {"POSId":"a123456-b123-c123-d123-e12345678901","LocationId":"88888","MerchantId":"POSDK99999"}
TimeStampUtc: 1413794400

Input to HMAC:
https://localhost:9003/API/V07/PaymentCancel {"POSId":"a123456-b123-c123-d123-e12345678901","LocationId":"88888","MerchantId":"POSDK99999"} 1413794400

You can use this online tool to test how to calculate HMAC:

For the textbox on the above test webpage, use:
https://localhost:9003/API/V07/PaymentCancel {"POSId":"a123456-b123-c123-d123-e12345678901","LocationId":"88888","MerchantId":"POSDK99999"} 1413794400

For the Key field (ApiKey), use:

Use the button: "Calculate Header HMAC"

The calculation steps are explained in more detail if “Explain calculation” is expanded

It is assumed that all input texts are trimmed for leading and trailing white space.
Note: Amount always contains 2 decimals, and the decimal point is always a period (not a comma!). Remember that that the alias is a calculated value:

Payload calculation:

var inputValue = String.Format("{0}#{1}#{2}#{3}#{4}#",
                amount.ToString("0.00", CultureInfo.InvariantCulture),
var alias = MerchantId + LocationId;
//The merchant key is calculated like this:
public byte[] GetMerchantKey(string alias)
    var merchantIdSub = alias.Substring(3, 6);
    var iso = Encoding.GetEncoding("ISO-8859-1");
    var utf8 = Encoding.UTF8;
    var utfBytes = utf8.GetBytes(merchantIdSub);
    var isoBytes = Encoding.Convert(utf8, iso, utfBytes);
    var sha256Cng = new SHA256Cng();
    var merchantKey = sha256Cng.ComputeHash(isoBytes);
    return merchantKey;
//The hmac body is calculated like this:
public string CalculateHmac(string payload, byte[] merchantKey)
    var inputBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(payload);
    //Compute hmac
    using (var hmacsha256 = new HMACSHA256(merchantKey))
        var hashmessage = hmacsha256.ComputeHash(inputBytes);
        return Convert.ToBase64String(hashmessage);

All HTTP MobilePay PoS method requests must comply MobilePay authorization header with HMAC method. 

OrderId: "123A124321"
PoSId: "a123456-b123-c123-d123-e12345678901"
MerchantId: "POSDK99999"
LocationId: "88888"
Amount: "43.33"
BulkRef: "MP Bulk Reference"


The MerchantKey is currently calculated as the following, based on MerchantId provided by MobilePay:
MerchantKey = SHA256(ISO-8859-1({Substring(MerchantId, 3, 6)}))
The substring of the MerchantId is calculated by skipping the first 3 characters and using the next 6 characters.

Input to HMAC
POSDK9999988888#a123456-b123-c123-d123-e12345678901#123A124321#43.33#MP Bulk Reference#

Note that the fields must be trimmed for leading and trailing white space.

Calculated Base64 HMAC

Max field lenght


Max length


String 10


String 5


String 35


String 15

Merchant Name

String 20

Location Name

String 30

PoS Name

String 15


String 18


String 32 max 18 is stored


String 256


String 20


String 32


String 32


Number – Decimal (18,2)


A callback URL must be configured, but only for payments.

For agreements you are passing callback URL together with agreement data, which is thy there is not a need for additional configuration for agreements. 

You’ll see all the callbacks on our GitHub documentation

  • Agreement callbacks are found here
  • Payment callbacks are found here
  • One off callbacks are found here
  • Refunds callbacks are found here

You will use the callback and callback status text to decide, whether the payment has been executed or not.

Available parameters for update are: 

  • amount
  • plan
  • description
  • next_payment_date
  • frequency
  • external_id
  • success-callback
  • cancel-callback

Customer needs to approve agreement on creation and that's it. After that merchant can send an update agreement operation and update/change some properties, but not all.  Customer doesn't need to approve agreement updates.

You'll find the technical documentation on GitHub here  

The API reference for the Subscriptions Api in sandbox is here and for production API is here

Is it possible to have the agreement accepted, but the payment not reserved? The scenario would be if we created an agreement with OneOff payment, but the customer does not have enough money for us to reserve (i.e. failed payment). In this case, what would happen?

If we are not able to reserve the payment (due to insufficient funds or blocked card), the user cannot accept the agreement. However, they have the option to change card, and hopefully have a card which can be used (this is most often the case). If this is not an option, the agreement will expire (you will receive a callback about this), and you need to make a new agreement.


Subscriptions - One-Off

User cannot cancel the agreement with a pending payment reservation. Only the Merchant can do so.
By cancelling the agreement with pending payment reservation, the  Merchant automatically cancels the reservation.

You will get callbacks about the payment to your payment callback URL. Moreover, you will get callbacks about the agreement to either success or failure url you have set upon agreement creation. However, you will not get callbacks for either, before their status changes. So you should expect a callback when the agreement is accepted/rejected/expired and a callback when the OneOff is either accepted/rejected/expired.

The response for agreement creation on the other hand, consist of both agreement and OneOff.

Subscriptions Agreement with One Off:

  • Use it when the user wants to set up an agreement and you want to charge upfront. I.e. iTunes subscription which starts to be effective from the moment money is paid.
  • You will use this when you want the customer to pay for the first month. Read more here
  • Initiated by User / redirect needs to happen for user to accept it.

Subscriptions Payment:

  • Use it when you need to charge recurring/periodic payment.
  • This is the only type of payment merchant has ability to initiate. And this will end up within users app at least 1 day prior to duedate.

Subscriptions Agreement: 

  • You can use this when you want the first month to be free. You can read more about it here

Subscriptions One-Off payment:

  • Use it when user has active agreement and wants to order extra services/products. I.e. on top of iTunes subscriptions to rent a movie.
  • Initiated by User / redirect needs to happen for user to accept it.
  • One-off invoices are used to request payment for specific goods or services. For example, you might invoice for a delivery of physical goods.


No. You can use One-off-Payments either during signup for a Subscription (like pay-now and allow merchant to make subscription payments each month) and you can use One-off-payments on customers that already have MobilePay to an existing Subscription (e.g. customer pays automatically each month but buy additional stuff in your “mit3.dk” environment).
Note that MP users approves each one-off payment
Merchant can capture a reserved payment asap. There is no need to wait for the confirmation about Reserved payment. 

Subscriptions - Parameters

  • If agreement was created successfully, we will POST you at the link rel=" success-callback";.
  • If user has canceled the flow, we will do a POST to link rel="cancel-callback".

    When the agreement creation flow is complete, the agreement status will be changed to "Accepted". Regardless of whether agreement was accepted or rejected user will be navigated to link rel=" user-redirect".

parameters type required Description  
retention_period_hours int   Before retention period has passed User will not be able to Cancel an agreement Min: 0(default), max: 24 hours


type required description valid values


boolean   If true user will not be presented with notification parameter, therefor will not be able to enable notifications. Default false

The end-user will see this screen:

and then this: 

When user cancels an Active agreement - sequence diagram

Link here 


Agreement status changed to Canceled

Payments should be refreshed (pending payment will be canceled)

Parameter Type Required Description Valid values
description string(60)   Additional information provided by the merchant to the user, that will be displayed on the Agreement screen.  

Note: This is visible on the payment screen, so ensure that the information provided makes sense towards the end-customer. 

Different use cases 

  • Merchants who are selling memberships to services such as gym membership, they usually just state 'membership'.
  • Merchants who are selling services on a recurring basis, such as an internet subscription, they include in the description the concrete service they are providing, such as 'internet'

Read more about this request parameter on GitHub here


You do not need to declare next_payment_date, unless you know the date for next_payment_date. We do not validate on next_payment_date.
However, it is something that is visible on the customers agreement screen in the app, if you have filled in the next_payment_date and if the first payment date > current date.

We have just two validations for subscription payments:

  • The customer should have at least 1 day to assess the payment, so if you send a subscription payment today, the due date should be at least 1 day in the future (i.e. the 1 day rule).
  • You can send a subscription payments to us max. 32 days before the due date.

So for the next month/period you need to create new payment requests again.


Parameter Type Required Description Valid values 
next_payment_date date   The date of the first scheduled Payment Request. This will be displayed on the Agreementcreation screen and on the Agreementdetails screen if first payment date > current date. ISO date format: yyyy-MM-dd
  • The focal point is, that the agreement "frequency" provides informational value to the customer. The frequency does not impact, how often you can send payments.
  • Agreement frequency.  Merchant can set frequency: dailyweekly, or flexibleSee more.
  • Subscription payment has a 1 day rule validation 

 If you set it to daily, it will display it as 'fleksibelt'

Parameter Type Required Description Valid values 
frequency int  

Frequency of Payment Requests.

This value will be used to divide the amount of days in a year to get a frequency in days (e.g. 365 / 12 = 30.4 - approx. every month, 365 - daily and 0 -flexible.)

1, 2, 4, 12, 26, 52, 365, 0

"External_id" for agreements

  • It is possible to update the external_id. But the parameter is meant as a unique identifier, chosen by the merchant, which shouldn’t change. On our side we have the "agreement_id, which never changes regardless of what happens to the agreement. That is the counterpart to the external_id on your side. It should stay the same, so we can trace the full history of the agreement. 
  • The customer can see the external_id in the app.
  • Our recommendation is, that the external_id is the users agreement id or reference with you. So that it does not seem confusing for the user. And if they have more than one Subscriptions agreement with you, they should be able to see which Subscriptions agreement is connected to which merchant agreement.
  • The external_id is included in the request body of the success and cancel callback. 
  • Maximum length is 64 characters

external_id for payments 

  •  When utilizing callbacks, it is important that you evaluate your usage of external_id, as it will be included in the request body of the refund callback, as well in the reference number and bank statement. The merchant is responsible for setting the external_id. If the merchant is using instant transfer, then the reference number will be the external_id for recurring payments and one-off payments. Merchant can set Instant transfers themsleves in the MobilePay Portal. Read more about reconciling subscriptions payments here
  • The customer can also see the payment external_id in the app. 
  • Our recommendation is that the external_id is unique for each payment.
  • Maximum length is 30 characters (this will soon be larger).

external_id for refunds

Updating the external_id

  • This is done using the PATCH /api/merchants/me/agreements/{agreementId} endpoint.

expiration_timeout_minutes defines how long time, the user have to initiate agreement acceptance.  Specifically, when they will directed to our landing page. It does not affect the timer they see after they have entered their phone number on our landing page. The timer is always set to 5 minutes, and it starts as soon as the user enters the phone number and clicks "Fortsæt". 

It is actually the time, they have to swipe in the MobilePay app. Which happens right after they click "Fortsæt", because this initiates the push notification to the app. So if you set expiration to 30 minutes, the user have 30 minutes from when you create the agreement until they must have clicked "Fortsæt" and swiped in the app.

  • Is the the "mobile_phone_number" required for agreement and one-off creation? 
    • In the example of the agreement request https://mobilepaydev.github.io/MobilePay-Subscriptions/agreement#requests there is a mobile_phone_number.  
    • Mobile_phone_number is not required, both for agreements and one-off. Neither for agreement creation, or one-off creation. If you choose to add it, the phone number will be prefilled on our landing page. So that the user will not have to type in the phone number here:
    • So it is slightly more convenient for the user, if you add mobile_phone_number.

It is a "nice to know" information for the customer about their subscription. It is visible for the customer, when they click on "Aftale" under "Betalingsaftaler" menu. The purpose is to inform the customer, what they are paying for. 

What is it used for? It depends on the customer's business model. For 3 Mobile, the plan could be defined as "Mobil and Bredbånd", since that is what the customer is paying for.  

Is it a mandatory field? Yes - especially from a customer perspective, as it is nice for the customer to be able to go into the app, to see which product or plan, they are paying for. It is a required field in terms of MobilePay Subscriptions. 

Are there default values? for example: Basic, Medium, Super? There are no default values. The merchant decides the values, as they know best, what their customer is paying for. For example: a newspaper can have the value "Digital" if it is a digital subscription and "Paper" if it is a paper-based subscription. 

Who can modify the contents? If you have an integrator, you need to ask the integrator to do so. If you are managing the solution yourself, you simply make an api call and update the existing Agreement using PATCH /api/merchants/me/agreements/{agreementId} endpoint to change agreement request parameters.  Its request must match the rules of RFC 6902 JSON Patch standards.


Parameter Type Required Description Valid values 
plan string(30) required Short Agreementinformation text, that will be displayed on theAgreementscreen. (examples: “Basic” / “Premium”).  
  • Who sets the agreement amount? The merchant decides the amount on each payment request
  • Can the amount vary from month to month? yes it can be variable parameter. Variable costs are costs that vary with output. For example: electricity will vary to a certain extent, depending on how much electricity the customer is using, which is why an electric bill will fluctuate each month. 
  • Where is it shown? The agreement amount will be displayed for the user in the MobilePay app under the agreement screen.
  • How do I update the amount? This is done using the PATCH / api/merchants/me/agreements/{agreementId} endpoint
  • What do you recommend? MobilePay recommends you include the amount, if the customer pays a fixed amount every month. If the merchant use case entails that the customer pays a varied amount, then you can either omit this parameter or patch the amount when/if the customer is paying higher or a lower amount 



Parameter Type Required Description Valid values
amount number(0.00)   Agreement amount, which will be displayed for the user in the MobilePay app. >= 0.00, decimals separated with a dot.

Subscriptions general

Pagination_state is a key, that indicates, how many pages have already been collected, and which pages are the next. With every request, you will receive a pagination_state, that you should use in the subsequent request. 

Both page_size and pagination_state are 'optional' in GET /subscriptions/api/providers/{providerId}/agreements, so if you haven't included it, you will have all agreements returned.

  • pageSize=<integer_value> - this defines how many agreement rows will be returned by single request (the limit is 2000).
  • paginationState=<token> - pagination token returned by previous request, should be empty for the very first request and should be url-encoded when present.

You will find the callbacks on GitHub, where there are callback_status_text for each.

  • Callbacks for agreements are found here. When the Agreement’s status changes from Pending we at MobilePay will do a callback to your system


User can’t cancel agreement if Reserved payment exists.

You can find the callbacks for Agreement changes here

Agreement state diagram

Yes. Multiple agreements with the same merchant is allowed for the customer. 

How do we administrate MobilePay Subscriptions? 

You do so on the MobilePay Portal

Within the Subscriptions product, you can "opret nyt betalingssted" which entails: 

  • upload a logo 
  • register name (the one that is shown in MobilePay app)
  • register e-mail adress for customer support
  • register landing page 


Can I have more than one Subscriptions Provider?

It is possible to have more than Subscriptions Provider. It is up to the merchant.  Before using MobilePay Subscriptions, the merchant must have at least one Subscriptions provider which can be created via MobilePay Portal. Each subscriptions provider contains its own address information, homepage url and callback url. 

HTTP 200 Response body example

     "Id" : "a863d62e-d53b-4651-9b7b-c80792ee1343"        
"SubscriptionProviders": [ { "SubscriptionProviderId": "b45afee5-703c-4136-8f60-162fc01709df", "Name": "Name of your subscription product", "HomepageUrl": "https://merchant.dk", "CustomerServiceEmail": "customerservice@merchant.dk", "SelfServicePortalUrl": "https://merchant.dk/self-service", "FaqUrl": "https://merchant.dk/faq", "Status": "Enabled"||"Pending", "Address": "Your address line", "ZipCode": "1234", "City": "City" } ] } ]


Updating subscription provider

Before requesting payments a status callback URL must be set by calling PATCH /api/providers/{providerId}:

Payment status callback URL


You register for MobilePay Subscriptions here 

You'll find the information on the general MobilePay website here 

One agreement with MobilePay entails one CVR-number. However, you can have more than 1 merchants under the same CVR number.  For example: JP/Politikens Hus publishes Jyllands-Posten, Politiken and Ekstra Bladet. They are all on MobilePay Subscriptions. 

The providerID, is retrieved from this endpoint 


existing in “Subscriptions Integrator” product. It will give you all providers existing under that “access token”.

  • You will get configuration details: payment_status_callback_url, scheme, key, password, scope.
  • Providers represents your customers (which is a MobilePay Merchant) providerId represents a particular subscription provider (for example, if a single merchant has several brands, each brand would be a subscription provider). Currently, a merchant grants you permissions to all their subscription providers, so once you get an access token, first thing you need to do is call GET /api/merchants/me which will return you a list of subscription providers for that merchant, with their IDs and basic information
If you sign up customer in your own systems (either face-to-face or via telephone) you are able to trigger our “desktop/tablet” flow. The screen below shows how you can type in Customers phone number = generates a notification to customer with approve that MobilePay is connected to a subscriptions agreement. 
MobilePay Subscriptions Dual Device

The Push Notifications window: 08:30 - 22:00 DK time. The following notifications are relevant to remember: 



Visuals / text 


General Reminder



One day before the due date at 08:30 DK time

Update Card 


Card is expired or about to expire before the due date.


8-1 days before the due date, 08:30

DK: Vi kan ikke gennemføre din betaling - dit betalingskort er udløbet


Daily limit exceeded, increase to NemID





 Din daglige beløbsgrænse er nået - klik her for at forhøje den 

Other issues with Payment card

 Other issues with Payment card, blocked, insufficient funds.

EN: We cannot complete your payment - click here to help us

DK: Vi kan ikke gennemføre din betaling - klik her for at hjælpe os

FI: Maksua ei voida suorittaa – Klikkaa tästä auttaaksesi meitä

Payment in other hiccup state - user can approve manually   

 DK: Vi kan ikke gennemføre din betaling - klik her for at hjælpe os




Agreement disable_notification_management push notification. Merchant can set if their customer should be able to manage push notifications for an agreement or not. If the merchant choses so, then the push notification is not displayed when signing new agreement and when browsing agreement information. This parameter is not required, and the default value is ‘false’ See more 



Subscriptions Payment Flow

How callbacks works  

  • You get notified about the agreement and payment status via REST callbacks.
  • You have real-time information about your customer agreement and subscriptions 
  • We are sending callbacks in two ways:
    • A batch that runs every 2 mins. It contains Subscription payments with status: Declined/Rejected/Failed/Executed/OneOff_Expired. So in theory, there is a possible delay of 2 mins.
    • Right after the user made an action. It contains OneOff_Reserved/OneOff_Rejected.
  • Every two minutes we take up to 1000 events (notifications about payment state), group them by merchant and make the calls. Therefore, as for merchant you should get up to 1 call every two minutes.
  • We will post the integrator or merchant a callback, and expect a HTTP 2xx response. If not we will retry 8 times.
  • For example:
    • Agreement: When the Agreement’s status changes from Pending we will do a callback to the merchant’s system
    • Payment: If a payment changes status e.g. declined by users, a callback on the specific payment will be made


  • You set the payment_status_callback_url yourself by making a call to our API. Go to -> APIs -> Subscriptions and find the  patch method to set the payment_status_callback_url
  • We cannot send callbacks to you, unless you have set the payment_status_callback 
  • The payment_status_callback_url does not need to be whitelisted at MobilePay side. 

Example of body (please insert your values)

   "value": "http://example.com",
   "path": "/payment_status_callback_url",
   "op": "replace",
   "from": "http://example.com"


What should I do if my system was not able to receive or correctly process the callback? 

  • The callback service will try to deliver its message through our retry mechanism - we make up to 8 retries. 
  • When a callback goes through whole cycle of multiple retries, it ends up in MobilePay Error Queue. You do not access to this Queue. 
  • You should use our API to retrieve a current status of the entity. 
  • Please configure the payment_status_callback_url before you start to send payment requests.

Read more here

The user cannot cancel their connection with the merchant through MobilePay. They can solely disconnect their payment method. MobilePay is not a part of the agreement that the merchant has signed with the customer. The merchant will receive callbacks real-time, in case the customer unsubscribes to automatic payment in the MobilePay app. By default, the cancellation takes effect immediately. Afterwards you should clarify with the customer, how upcoming payments should be handled. You can still offer the customer to pay with MobilePay; the customer just needs to connect to MobilePay Subscriptions again.

The customer can see the payment as a future payment at least 1 day before DueDate. If the customers wants to be notified and the merchant has agreed to this, the customer can be automatically notified the day before, the payment is executed.


Payment state diagram

There are validation rules; however the payments are not validated until they have been created in our system. Therefore, even though you get a response with pending payments, they may not be valid.  When you make a payment request, we will validate the request itself, but not the individual payments. So it only validates if you have the required parameters with the correct types. So the response you get for the payment request, does not say if the payment is pending, but if the payment creation is pending. Then the payments are processed in our system, and they will either be requested (valid) or declined (invalid). Moreover, you will receive a callback to inform whether payments are requested or declined. This will be sent to your payment status callback  

You can find all of the callbacks for Subscription payments on a table on GitHub here 



You can choose a reference or ID on the subscriptions payments that your merchant sends via MobilePay Subscriptions. It is possible to do reconciliation in several ways.

  1. Callbacks: You get the status of the payment through the API callbacks. When the payment has status executed then the customer has paid, and MobilePay sends a callback to you. Callbacks for subscription payments are found here
  2. Mapping external_id The individual transactions will contain the same external_ID  , that you have assigned, and that  external_ID    will be returned through the API.  external_id is the identifier of a specific payment in merchant and integrator system, and can be used for this purpose. 
  3. MobilePay Portal: The merchant logs in to our MobilePay portal on https://admin.mobilepay.dk where you can export the transactions in a CSV file.  This method is quite manual, and the Merchant is the only one that has access to the MobilePay portal. The integrator does not have access to it. 
  4. Use the Transaction Reporting API which contains GET calls containing specific transaction and transfer information. For MobilePay Subscriptions, you should look for the parameter.  MerchantReference  as it is equivalent to external_id 

For example, if the merchant wants to use their FIK-Creditor-ID for transactions, then you simply choose the reference number, which can be the merchant FIK Creditor ID. There are no special requirements for the merchant FIK creditor-ID to be able to use it for MobilePay Subscriptions.

It means that you can not withdraw the money from the customers payment card, and then the payment gets suspended. It tries 6 times during the duedate. If the problem persists, and there is not sufficient funds on the customers cards, or if the card is expired or etc, then the payment will fail. Suspended is a status internally for MobilePay to mark hiccupped payments, which is why it is not a part of the callback table on the documentation on GitHub

Note: MobilePay does not tell you the specific reason why there are troubles with the card, as we are not allowed to give that level of detail. 


In short, the Merchant should contact the customer, and have it cleared out with the customer. 


The user receives a push notification, if there was an error with the card for example, so we always try to catch errors.

If there were insufficient funds on the customers card, we also push the customer to execute the payment manually.

How do I create an agreement? 

  • You can allow customers (MobilePay users) to connect their MobilePay to a Subscription agreement with a Merchant by calling the API with minimum input fields required. You do not need to know the "amount", "next_payment_date" or "mobile_phone_number".
  • The links are used to redirect user from MP app back to merchant web environment. 
  • In return of the API call, you will get at link that must be wrapped in a “Pay with MobilePay" button.
  • Once customer clicks on the  “Pay with MobilePay" button our landing page determines if the customer is using a mobile device or desktop/tablet.
    • If the customer is using a mobile device, then the MobilePay app opens.
    • If the customer is using a desktop/tablet, then our MobilePay landing page will have a window for the customer to enter mobile number and generate at notification to the MobilePay app. If the customer already have filled out mobile number at merchants environment you can choose to fill out “mobile_phone_number” then this field fill be prefilled on landing page (so customer does not need to fill in same details twice). 
  • When the customer accepts in MobilePay (by swiping) you get a unique “agreement_id” back that you must store along with your customer e.g. "fda31b3c-794e-4148-ac00-77b957a7d47f"


You will find the callbacks on GitHub, where there are callback_status_text for each.

  • Callbacks for subscription payments are found here
  • User-redirect: You set this redirect for each agreement you create. It can't be changed afterwards. 
  • Succes-callback: You set this redirect for each agreement you create. It can be changed afterwards. 
  • Cancel-callback: You set this redirect for each agreement you create. It can be changed afterwards. 



Agreement and checkout flow 

Please ensure that your usage of user-redirect is well implemented at the merchant side. When the Agreement activation is complete or canceled, the user will be navigated to the link rel = user-redirect to finalize the signup.

Links must contain 3 values for user redirect. Read more here:

Link relation of the Agreement creation sequence.

 Link Customer scenarios  This will result in  The customer experiences



  • User swiped to accept the Agreement 
Callback to merchant system   



  • User tapped the cancel button during the signup
  • User did not do anything during the agreement timeout period
  • User canceled an Active agreement
  • Merchant canceled an Active agreement
  • System canceled an Active agreement because user was Deleted

Callback to merchant system 

Read more here which screens the customer sees, when/if they cancel their subscriptions agreement. 



  • When the agreement activation is complete or canceled, the user will be navigated to the link rel = user-redirect to finalize the sign-up. We recommend that you display the One-Off payment and agreement result. 
  • It should be a webpage, that awaits the callbacks and then takes appropriate action, depending on if the agreement was accepted or not. Based on the callback, you will redirect the user to the right place. 
  • Most merchants navigate the customer to a self-service overview, where the agreement is pending, and once you receive the callback, then you can update the status. Most merchants have a general page, that says “thank you for your order/support”, and then it informs about the next step. It is triggered immediately after purchase, letting customers know that their order and agreement has been received and created

The user being redirected to a page, that the merchant has defined


Please define those URL's specifically so the user experience is optimised. The callback is triggered real-time. user-redirect is a HTTP GET and callback is HTTP POST 

 Callbacks for Agreements  
New Status Condition URL Callback status Callback status_text Callback status_code
Accepted  User swiped to accept the Agreement  success-callback Active    0 
Rejected User rejected agreement in the APP  cancel-callback Rejected  Agreement rejected by user 40000 
Expired User did not do anything during the agreement timeout period.  cancel-callback Expired  Pending agreement expired 40001 
Canceled User canceled an Active agreement cancel-callback Canceled  Agreement canceled by user 40002 
Canceled Merchant canceled an Active or Pending agreement cancel-callback Canceled  Agreement canceled by merchant 40003 
Canceled System canceled an Active agreement because user was Deleted cancel-callback Canceled  Agreement canceled by system. 40004 

You do not get a callback that tels you specifically if/when the user closes the landing page with the timer. 


  • payment_status_callback_url: You set this for each provider, and you can change it whenever. You can change it on the fly. 

As an integrator, you should set the "payment_status_callback_url" for each subscriptions provider, and then MobilePay uses it, when there are updates on payments. 

An example of body that you should use (just with your own values)



    "value": "http://example.com",

    "path": "/payment_status_callback_url",

    "op": "replace",

    "from": "http://example.com"


It is a PATCH method

Those do not need to be whitelisted at MobilePay.

MobilePay has an agreement with a PSP (payment service provider). We at MobilePay take care of the process regarding execution of payments etc. 

The merchant can test as much as they want in sandbox environment, but the merchant will start paying transaction fee in production, as well as "hidden production".

Once the merchant is in production, they will start to pay for production transactions as well. 

There are validation rules; however the payments are not validated until they have been created in our system. Therefore, even though you get a response with pending payments, they may not be valid. When you make a payment request, we will validate the request itself, but not the individual payments. So it only validates if you have the required parameters with the correct types. So the response you get for the payment request, does not say if the payment is pending, but if the payment creation is pending. Then the payments are processed in our system, and they will either be requested (valid) or declined (invalid). Moreover, you will receive a callback to inform whether payments are requested or declined. This will be sent to your payment status callback URL.

There is no admin panel or any kind of interface for you to check requests, instead there are several API calls:

  • Get a list of agreements - GET /api/merchants/me/agreements
  • Get agreements details - GET /api/merchants/me/agreements/{agreementId}
  • Get a list of payments in a given agreement - GET /api/merchants/me/agreements/{agreementId}/paymentrequests
  • Get details on a single payment - GET /api/merchants/me/agreements/{agreementId}/paymentrequests/{paymentId}
  • Get all OneOff payments of a single agreement - GET /api/merchants/me/agreements/{agreementId}/oneoffpayments
  • Get details on a single OneOff payment - GET /api/merchants/me/agreements/{agreementId}/oneoffpayments/{paymentId}
  • Get a list of refunds issued for particular payment - GET /api/merchants/me/agreements/{agreementId}/payments/{paymentId}/refunds
  • Batch details: a batch request contains of multiple API calls combined into one HTTP request. 
  • Requestpayment endpoint accepts an array of payment requests. Batch is more readily processed than single, individual calls, because single calls results in extra load. 
  • You can batch payment requests into payloads of max 2.000 payments. We allow merchants to bundle multiple payment requests into a single http request.
  • You get an answer on the payments that are executed in the first batch and later in the day, in case there are more payments that are executed.  

Subscriptions Callbacks

We are sending those in two ways:

  1. A batch that runs every 2 mins. It contains subs payment with statuses: Declined/Rejected/Failed/Executed/OneOffExpired. So in theory, there is a possible delay of 2 mins. 
  2. Right after the user made an action. It contains OneOff_Reserved/ OneOff_Rejected

Every two minutes we take up to 1000 events (notifications about payment state), group them by merchant and make the calls. Therefore, as for merchant he should get up to 1 call every two minutes.

We will post the integrator or merchant a callback, and expect a HTTP 2xx response. If not we will retry 8 times.

  • You can send your payments to us max. 126 days before due date and min. 1 day before due date
  • The MobilePay user will be able to see Payments in the app min. 1 day before due date 
  • If a payment changes status e.g. declined by user, a callback on the specific payment will be made.
  • On due date we process the payments starting from 02:00. If some payments are declined we will then try again approx. every 3 hours up until 23:59.
  • If errors processing the payment, user will get at notification approx. at 08:30 that we can not process payment and that he/she can complete the payment manually (by correcting the error and swipe) 
  • On 23:59 we will decline the transaction and revert back with a callback. 

Subscriptions payments are collected automatically, so there is no need for the customer to swipe.

Subscriptions API - Transfers

It is important to know which transfer type are possible to use as a merchant. There are two:

  1. Instant Transfer
  2. Daily Transfer


Instant Transfer

Daily Transfer


  • MobilePay transfers instantly after the payment is completed.
  • Transfer might reach Merchant account later then MobilePay executes transfers. It depends on Merchant bank transfer times.
  • MobilePay transfers once per day, at night. Payments payed on day X will be transferred on day X+1.
  • Transfer might reach Merchant account later than MobilePay executes transfers. It depends on Merchant bank transfer times.


  • Field external_id for recurring payments and one_off_payment. external_id for one-off payments is used as Reference number.
  • Reference number is generated by MobilePay.
  • External Rules here.


  • Merchant can set Instant transfers for each Subscription provider in MobilePay portal.
  • Merchant can set Daily transfers for each Subscription provider in MobilePay portal.


  • external_id for recurring payments and one_off_payment.external_id for one-off payments will be used in bank statement in fields:
    • DK Text field.
    • FI Text field and Reference no. field.
  • MobilePay generated reference number will be used in bank statement in fields:
    • DK Text field.
    • FI Text field and Reference no. field.