MobilePay Subscriptions

OpenID Connect Flow

Overview

General Notes

Agreements

Subscription Payments

One-Off Payments

Refunds

Invoices

Mutual SSL Flow

Overview

General Notes

Agreements

Subscription Payments

One-Off Payments

Refunds

Release Notes

Subscriptions Integrator 1.1

Overview

Billing your customers has never been easier before. This document explains how to make a technical integration to the MobilePay Subscription product. The audience for this document is either technical integrators acting on behalf of merchants. You can find more information on our Developer Portal.

Our MobilePay Subscriptions REST api enables you to:

  1. Establish and manage Agreements between you, the Merchant, and MobilePay Users.
  2. Create monthly Subscription Payments in relation to an established Agreement and get notified about the status via REST callbacks. Subscription Payments are requested 8 days before the actual booking date - no manual user confirmation required!

Related links:

QuickStart: follow our QuickStart to start building your integration

Merchant onboarding

You enroll to the Subscriptions Production via www.MobilePay.dk or the MobilePay Business Administration portal. Then you get access to the MobilePay Sandbox environment, where you can test the technical integration. The environment is located on The Developer Portal

Authentication

OpenID Connect

When the merchant is onboarded, he has a user in MobilePay that is able to manage which products the merchant wishes to use. Not all merchants have the technical capabilities to make integrations to MobilePay, instead they may need to go through applications whith these capabilities. The OpenID Connect protocol is a simple identity layer on top of the OAuth 2.0 protocol.

Client: In order for this to work, the merchant must grant consent to an application(Client) with these capabilities. The client is the application that is attempting to get access to the user’s account. The client needs to get consent from the user before it can do so. This consent is granted through mechanism in the OpenID Connect protocol suite.
Integrators are the same as Clients in the OAuth 2.0 protocol. The first thing that must be done as a Client is to go and register here. Once this is done the Client must initiate the hybrid flow specified in OpenID connect. For Subscriptions product the Client must request consent from the merchant using the subscriptions scope. Scopes are like permissions or delegated rights that the Resource Owner wishes the client to be able to do on their behalf. You also need to specify offline_access scope, in order to get the refresh token. The authorization server in sandbox is located here.
If the merchant grants consent, an authorization code is returned which the Client must exchange for an id token, an access token and a refresh token. The refresh token is used to refresh ended sessions without asking for merchant consent again. This means that if the Client receives an answer from the api gateway saying that the access token is invalid, the refresh token is exchanged for a new access token and refresh token.

An example of how to use OpenID connect in C# can be found here.

When user clicks on this button, merchant must do back-end call to
"/authorize" endpoint for initiating authentication flow. You need to wait for the response by listening on the redirect URI and get the Authorization Code. Our system will re-direct the merchant back to your system also using the redirect URL.

In short - The flow is described in the following 4 steps:

Step 1: Call /connect/authorize to initiate user login and consent

Step 2: Wait for the response by listening on the redirect URI and get the authorization code

Step 3: Exchange the authorization code for tokens using /connect/token

Step 4: Keep the session alive by using the refresh token

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

In order to authenticate to the API, all requests to the API must contain at least three authentication headers:

  1. x-ibm-client-id
  2. x-ibm-client-secret
  3. Authorization
$ curl --header "Authorization: Bearer <token>" --header 'x-ibm-client-id: client-id' --header 'x-ibm-client-secret: client-secret' --url https://<mobile-pay-root>/api/merchants/me/resource

OpenID flow

Implementing OpenID Connect protocol

Although the protocol is not that complicated, there is no need to implement it yourself! There are many OpenID Connect certified libraries for different platforms, so you just have to chose the one, that suits you best from this list.

General notes

MobilePay Subscriptions is a full-fledged HTTPS REST api using JSON as request/response communication media.

All dates and time-stamps use the ISO 8601 format: date format - YYYY-MM-DD, date-time format - YYYY-MM-DDTHH:mm:ssZ.

Amounts are enquoted with double quotation marks using 0.00 format, decimals separated with a dot.

When doing POST, PATCH or PUT requests, Content-Type: application/json HTTP header must be provided.

$ curl --request POST --header 'Content-Type: application/json' --url https://<mobile-pay-root>/resource --data '{}'

Errors

You might encounter the following HTTP errors:

  1. 400 - Bad Request , if request data is invalid.
     {
         "error": "BadRequest",
         "error_description": {
             "message": "request.Name is required",
             "error_type": "InputError",
             "correlation_id": "f4b02597-32cc-420f-a468-942307e89a97"
         }
     }
    
  2. 404 - Not Found with no response body, if the resource (agreement or payment) is not found.

  3. 412 - Precondition Failed , if business validation rule was violated.
     {
         "error": "PreconditionFailed",
         "error_description": {
             "message": "Duplicate payment.",
             "error_type": "PreconditionError",
             "correlation_id": "f4b02597-32cc-420f-a468-942307e89a97"
         }
     }
    
  4. 500 - Internal Server Error , if something really bad has happened.
     {
         "error": "InternalServerError",
         "error_description": {
             "message": "An error occurred, please try again or contact the administrator.",
             "error_type": "ServerError",
             "correlation_id": "f4b02597-32cc-420f-a468-942307e89a97"
         }
     }
    

REST request correlation

CorrelationId is an optional Guid header value which can be used to link requests on your back-end system to MobilePay Subscriptions business transaction for a more convenient debugging.

$ curl --header 'CorrelationId: 37b8450b-579b-489d-8698-c7800c65934c' --url https://<mobile-pay-root>/api/merchants/me/agreements

Getting a list of subscription providers

After getting an access token, you will be able to list subscription providers associated with that merchant by calling GET /api/merchants/me, which will return a list of all subscription providers, associated with that merchant.

Providers represents your customer (which is a MobilePay Merchant). providerId represents a particular subscription provider.

For example, if a single merchant has several brands, then each brand would be a subscription provider. Currently, a merchant grants you permission to all their subscription providers.

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

[
    {
        "value": "https://merchant.dk/notifications_from_mobilepay/payments",
        "path": "/payment_status_callback_url",
        "op": "replace"
    }
]

REST callback authentication

Use one of these endpoints to set REST callback authentication scheme and credentials:

REST callback retries

In case the REST callback failed, 8 retries will be made using the exponential back-off algorithm, where N - next retry time, c - retry attempt number, R - second retry time in seconds (1st retry is an exception and is done after 5 seconds):


Agreements

Once the user is given to choose the payment method on the merchant’s signup flow, an additional “Pay with MobilePay” button should be shown for the user to be able to click on. When user clicks on this button, merchant’s back-end system must call the POST /api/providers/{providerId}/agreements endpoint in order to create a Pending Subscription Agreement, which can only be activated by the MobilePay user through the app.

{
  "external_id": "AGGR00068",
  "amount": "10",
  "currency": "DKK",
  "description": "Monthly subscription",
  "next_payment_date": "2017-03-09",
  "frequency": 12,
  "links": [
    {
      "rel": "user-redirect",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "success-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "cancel-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    }
  ],
  "country_code": "DK",
  "plan": "Basic",
  "expiration_timeout_minutes": 5,
  "mobile_phone_number": "4511100118"
}

Mobile_phone_number is not required. 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 the phone number on the landing page, which makes it more convenient for the user, if you add mobile_phone_number.

The Pending Agreement, if not activated, will expire within the value, provided in the expiration_timeout_minutes.

Request parameters

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.
currency string(3) required The Agreement currency code, that will be displayed for the use in the MobilePay app. Currency and country_code must match a valid pair of: DKK->DK, NOK->NO, EUR->FI. DKK, NOK, EUR
country_code string(2) required Country code, which will be used to differentiate between MobilePay DK, NO and FI apps. DK, NO, FI
plan string(30) required Short Agreement information text, that will be displayed on the Agreement screen. (examples: “Basic” / “Premium”).  
description string(60)   Additional information provided by the merchant to the user, that will be displayed on the Agreement screen.  
next_payment_date date   The date of the first scheduled Payment Request. This will be displayed on the Agreement creation screen and on the Agreement details screen if first payment date > current date. ISO date format: yyyy-MM-dd
frequency int required 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.) 1, 2, 4, 12 or 26
external_id string   *Agreement identifier on the merchant’s and integrators side. This will be included in the request body of the success / cancel callback. The external_id should be unique to the agreement. Two different agreements should not have the same external_id *  
expiration_timeout_minutes int required Agreement expiration timeout in minutes. Min: 5, max: 20160 (2 weeks)
links string required Link relation of the Agreement creation sequence. Must contain 3 values for user redirect, success callback and cancel-callback links.  
links[].rel string required Link relation type. user-redirect, success-callback, cancel-callback
links[].href string required Link relation hyperlink reference. https://<merchant’s url>

The response of POST /api/providers/{providerId}/agreements contains two values: a unique id of the newly created Pending Agreement and a link rel = mobile-pay.

{
  "id": "1b08e244-4aea-4988-99d6-1bd22c6a5b2c",
  "links": [
    {
      "rel": "mobile-pay",
      "href": "https://<mobile-pay-landing-page>/?flow=agreement&id=1b08e244-4aea-4988-99d6-1bd22c6a5b2c&redirectUrl=https%3a%2f%2fwww.example.com%2fredirect&countryCode=DK&mobile=4511100118"
    }
  ]
}

The link can be used in two ways:

  1. Redirect the user automatically using the HTTP response 302 or 303. Once the user is redirected, the MobilePay app will be opened to activate the Pending Agreement. In this case, it is recommended to set the expiration_timeout_minutes value to 5 minutes.
  2. E-mail the generated link to the user. Once the user clicks on the link, the MobilePay app will be opened to activate the Pending Agreement. In this case, it is recommended to set the expiration_timeout_minutes to a higher value (10080 - a week, 20160 - two weeks). Note, that the link will be valid only until the user accepts the agreement or a timeout occurs.

Update existing Agreement Request

Use the PATCH /api/merchants/me/agreements/{agreementId} endpoint to change agreement request parameters. Its request must match the rules of RFC 6902 JSON Patch standards.

[
    {
        "value": "10.01",
        "path": "/amount",
        "op": "replace"
    }
]

New agreement creation in landing page

New agreement creation in APP

Callbacks

When the Agreement’s status changes from Pending we will do a callback to the merchant’s system (see the sequence diagram below).

The table below shows possible status, status_text and status_code values depending on the Agreement status changes.

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 tapped the Cancel button during the signup 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 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
Agreement state diagram

Other callback properties
Name Type Description Format
agreement_id guid Subscription agreement ID on the MobilePay side.  
external_id string Agreement ID on the merchant’s side  
timestamp datetime Timestamp when the status change occurred. ISO 8601 UTC date and time format: YYYY-MM-DDThh:mm:ssZ
Agreement callback request example
{
    "agreement_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea",
    "status" : "Canceled",
    "status_text" : "Canceled by user",
    "status_code" : "40000",
    "external_id" : "SF0000568",
    "timestamp" : "2016-09-29T09:50:39Z"
}
Agreement callback response properties
Name Description
agreement_id Subscription agreement ID on the MobilePay side.
status_code Status code on merchant’s system
status_text Description of the status.
transaction_id Unique identifier of the transaction on the merchant’s system.

status_code can have the following values:

The callback response properties are optional. In case of technical errors (HTTP response is not 2xx), we will try to re-POST the callback.

Agreement callback response example
{
    "agreement_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea",
    "status_code" : "3000",
    "status_text" : "Server is down",
    "transaction_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea"
}

When the Agreement activation is complete or canceled, the user will be navigated to the link rel = user-redirect to finalize the signup.

Agreement creation sequence diagram

When merchant cancels agreement - sequence diagram

When user cancels a Pending agreement during signup - sequence diagram

When user cancels an Active agreement - sequence diagram


Subscription Payments

When the Agreement between Merchant and MobilePay User is established, use the POST /api/providers/{providerId}/paymentrequests endpoint to en-queue Subscription Payments. This service accepts a JSON array of individual Subscription Payments to be processed asynchronously. You can batch payment requests into payloads of maximum 2000 payments. We allow merchants to bundle multiple payment requests into a single HTTP request. Notice that the Subscription Payments payload does not contain a currency code - this will be fetched from the Agreement using the provided agreement_id.

[
    {
        "agreement_id": "fda31b3c-794e-4148-ac00-77b957a7d47f",
        "amount": "10.99",
        "due_date": "2017-03-09",
        "next_payment_date": "2017-04-09",
        "external_id": "PMT000023",
        "description": "Monthly payment"
    }
]

How do Subscription Payments work?

Request parameters

Parameter Type Required Description Valid values
agreement_id guid required The Subscription Agreement identifier that maps a Merchant to a MobilePay User.  
amount number(0.00) required The requested amount to be paid. > 0.00, decimals separated with a dot.
due_date date required Payment due date. Must be at least 8 days in the future, otherwise the Subscription Payment will be declined. ISO date format: yyyy-MM-dd
next_payment_date date   Next Subscription Payment’s due date, to be shown to the user in the Agreement details. ISO date format: yyyy-MM-dd
external_id string required The identifier of a specific payment in the external merchant’s system. Maximum length is 30 characters  
description string(60) required Additional information of the Subscription Payment.  

The POST /api/providers/{providerId}/paymentrequests service returns HTTP 202 - Accepted response if at least one payment is provided in the request payload.

The response body containts two lists:

HTTP 202 Response body example
{
    "pending_payments": [{
            "payment_id": "263cfe92-9f8e-4829-8b96-14a5e53c9041",
            "external_id": "PMT000023"
        }
    ],
    "rejected_payments": [{
            "external_id": "PMT000023",
            "error_description": "The Amount field is required."
        }
    ]
}

Frequency of Payment Requests

The merchant can send a payment max 32 days prior due date, and at at least 8 days before due date. Valid values are 1, 2, 4, 12, 26. This means that the bi-weekly payment (26) is the most frequent. When you are requesting a payment, you need to keep the 8 day rule. The user can have a single pending payment on due date. E.g. User can have 3 pending payments but the DueDate of those payments should be different.

Example of Frequency

For example: if you have a customer where the frequency of an agreement is set to 4, that means 365 / 4 = 91.25 (approximately payment requests every 3rd month).

Payment screens

Callbacks

Once the payment status changes from Pending to Executed, Declined, Rejected or Failed, a callback will be done to the callback address, which is configurable via PATCH /api/providers/{providerId} with path value /payment_status_callback_url.

We are sending callbacks in two ways:

  1. 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.
  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 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.

[
    {
        "value": "https://example.com",
        "path": "/payment_status_callback_url",
        "op": "replace"
    }
]
New Status Condition When to expect Callback status Callback status_text Callback status_code
Executed The payment was successfully executed on the due-date After 03:15 in the morning of the due-date Executed   0
Failed Payment failed to execute during the due-date. After 23:59 of the due-date Failed   50000
Rejected User rejected the Pending payment in MobilePay Any time during the 8 day period when user is presented with the Pending payment in the MobilePay activity list. Rejected Rejected by user. 50001
Declined Merchant declined the Pending payment via the API Any time during the 8 day period when user is presented with the Pending payment in the MobilePay activity list. Declined Declined by merchant. 50002
Declined Agreement is not in Active state. Right after the payment request was received. Declined Declined by system: Agreement is not “Active” state. 50003
Declined If the Agreement’s frequency period has not passed since the last *Pending* or *Executed* Payment Request for that Agreement. Monthly agreements have a 1 week tolerance level. Right after the payment request was received. Declined Declined by system: Another payment is already due. 50004
Declined When the Agreement was canceled by merchant or by system Any time during the 8 day period when user is presented with the Pending payment in the MobilePay activity list. Declined Declined by system: Agreement was canceled. 50005
Rejected When the Agreement was canceled by user Any time during the 8 day period when user is presented with the Pending payment in the MobilePay activity list. Rejected Declined by system: Agreement was canceled. 50005
Declined A catch-all error code when payment was declined by core system. Right after the payment request was received. Declined Declined by system. 50006
Declined Declined due to user status. Right after the payment request was received. Declined Declined due to user status. 50009
Declined When the Agreement does not exist Right after the payment request was received. Declined Agreement does not exist. 50010
Declined When the due date before rule is violated Right after the payment request was received. Declined Due date of the payment must be at least 8 days in the future. 50011
Declined When the due date ahead rule is violated Right after the payment request was received. Declined Due date must be no more than 32 days in the future. 50012

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

The process on failed payments the DueDate is as follows:

• 06:00 First hiccup is run at 06:00 on the due date. Once done, a notification about completion is returned. Merchant is informed about successful payments and user about failed payment

• 13:30 Second hiccup is run at 13:30 on the due date. Once done, a notification about completion is returned. Merchant is informed about successful payments and user about failed payment.

• 18:00 20:00 22:30 - hiccups keep running throughout the day. Once done, a notification about completion is returned. Merchant is informed about successful payments and user about failed payment,

Suspended

It means that the you can not withdraw the money from the customers payment card, and then the payment gets suspended. It tries 6 times during the duedate. There can be various reasons why it can he suspended. If the problem persists, and there is not sufficient funds on the customers card, or/and if the card is expired or/and blocked, 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 above.

Solution : MobilePay sends the customer a push notification, if there was an error with the card, in order to catch errors. If there were insufficient funds on the customers card, we also push the customer to execute the payment manually. The Merchant should contact the customer, and have it cleared out with the customer.

Payment state diagram

Other callback properties
Name Type Description Format
agreement_id guid Subscription agreement ID on the MobilePay side.  
payment_id guid Subscription payment ID on the MobilePay side.  
amount number(0.00) Amount withdrawn from the MobilePay user.  
currency string Amount currency (agreement’s currency)  
payment_date date Date of the batch when the payment was executed. ISO 8601 UTC date: YYYY-MM-DD
external_id string Payment ID on the merchant’s side. Maximum length is 30 characters  
Payment callback body example
[
    {
        "agreement_id" : "1b08e244-4aea-4988-99d6-1bd22c6a5b2c",
        "payment_id" : "c710b883-6ed6-4506-9599-490ead89525a",
        "amount" : "10.20",
        "currency" : "DKK",
        "payment_date" : "2016-09-29",
        "status" : "Rejected",
        "status_text" : "Rejected by user.",
        "status_code" : "50001",
        "external_id" : "SFPMT134560"
    }
]
Payment callback response properties

An array containing the following properties.

Name Description
payment_id Subscription payment ID on the MobilePay side.
status_code Status code on merchant’s system
status_text Description of the status.
transaction_id Unique identifier of the transaction on the merchant’s system.

status_code can have the following values:

The callback response properties are optional. In case of technical errors (HTTP response is not 2xx), we will try to re-POST the callback.

Payment callback response example
[
    {
        "payment_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea",
        "status_code" : "3000",
        "status_text" : "Server is down.",
        "transaction_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea"
    }
]

Update existing Payment Request

Use the PATCH /api/providers/{providerId}/agreements/{agreementId}/paymentrequests/{paymentId} endpoint to decrease the requested amount to be paid.

[
    {
        "value": "10.01",
        "path": "/amount",
        "op": "replace"
    }
]

One-Off Payments

You are able to:

Note: Subscription payments are charged automatically, while one-off are charged when the customer manually swipes accept. OneOff payment does not affect the frequency and grace period. So if you create an agreement with a OneOff, you can request the first subscriptions payment whenever you want. You can also request a OneOff on an existing agreement in between two subscriptions payments, and it will not be affected by the frequency. But if you do it on an existing agreement, the user has to swipe to accept the payment. When you create an agreement with a OneOff, and the user accepts the agreement, the payment will be processed and executed right away. OneOff is an instant payment, and it is not subject to the 8 day rule.

User cannot cancel the agreement with pending payment reservation, only the merchant can do so.

By cancelling the agreement with a pending payment reservation, then the merchant also automatically cancels the reservation

Request One-Off Payment With a New Agreement

Add a one_off_payment property to the POST /api/providers/{providerId}/agreements request payload if you want the agreement being activated only when the user is successfully charged an initial subscription amount.

{
  "external_id": "AGGR00068",
  "amount": "10",
  "currency": "DKK",
  "description": "Monthly subscription",
  "next_payment_date": "2017-03-09",
  "frequency": 12,
  "links": [
    {
      "rel": "user-redirect",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "success-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "cancel-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    }
  ],
  "country_code": "DK",
  "plan": "Basic",
  "expiration_timeout_minutes": 5,
  "mobile_phone_number": "4511100118",
  "one_off_payment": 
    {
      "amount": "80",
      "external_id": "OOP00348",
      "description": "Down payment for our services"
    }
}

Newly added request parameters

Parameter Type Required Description Valid values
one_off_payment object   One-Off Payment details.  
one_off_payment.amount number(0.00) required One-Off Payment amount, which will be displayed for the user in the MobilePay app. > 0.00, decimals separated with a dot.
one_off_payment.description string(60) required Additional information provided by the merchant to the user, that will be displayed on the One-off Payment screen.  
one_off_payment.external_id string(30) required One-Off Payment identifier on the merchant’s side. This will be included in the request body of the payment callback.  

In this case the response of POST /api/providers/{providerId}/agreements will contain additional one_off_payment_id value - id of the newly requested One-Off Payment.

{
  "id": "1b08e244-4aea-4988-99d6-1bd22c6a5b2c",
  "one_off_payment_id": "2a5dd31f-32c1-4517-925f-9c60ba19f8ca",
  "links": [
    {
      "rel": "mobile-pay",
      "href": "https://<mobile-pay-landing-page>/?flow=agreement&id=1b08e244-4aea-4988-99d6-1bd22c6a5b2c&redirectUrl=https%3a%2f%2fwww.example.com%2fredirect&countryCode=DK&mobile=4511100118"
    }
  ]
}

Request One-off Payment on an Existing Agreement

Use a POST /api/providers/{providerId}/agreements/{agreementId}/oneoffpayments endpoint in order to charge your customer one time for extra services.

{
  "amount": "80",
  "external_id": "OOP00348",
  "description": "Pay now for additional goods",
  "links": [
    {
      "rel": "user-redirect",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    }
  ]
}

One-off Payment will expire in 1 day if it is not accepted or rejected by the user during that time.

Request parameters
Parameter Type Required Description Valid values
amount number(0.00) required One-off Payment amount, which will be displayed for the user in the MobilePay app. > 0.00, decimals separated with a dot.
description string(60) required Additional information provided by the merchant to the user, that will be displayed on the One-off Payment screen.  
external_id string required One-off Payment identifier on the merchant’s side. This will be included in the request body of the payment callback.  
links string required Link relation of the One-off Payment creation sequence. Must contain 1 value for user redirect.  
links[].rel string required Link relation type. user-redirect
links[].href string required Link relation hyperlink reference. https://<merchant’s url>

The response of POST /api/providers/{providerId}/agreements/{agreementId}/oneoffpayments contains two values: a unique id of the newly requested One-Off Payment and a link rel = mobile-pay.

{
  "id": "07b70fdd-a300-460d-9ba1-aee2c8bb4b63",
  "links": [
    {
      "rel": "mobile-pay",
      "href": "https://<mobile-pay-landing-page>/?flow=agreement&id=1b08e244-4aea-4988-99d6-1bd22c6a5b2c&oneOffPaymentId=07b70fdd-a300-460d-9ba1-aee2c8bb4b63&redirectUrl=https%3a%2f%2fwww.example.com%2fredirect&countryCode=DK&mobile=4511100118"
    }
  ]
}
One-Off payment screens

Callbacks

Once the one-off payment status changes from Requested to Reserved, Rejected or Expired, a callback will be done to the callback address, which is configurable via PATCH /api/providers/{providerId} with path value /payment_status_callback_url. The same way as with callbacks for regular payment requests.

New Status Condition When to expect Callback status Callback status_text Callback status_code
Reserved The one-off payment was accepted by user and money is reserved for you on his card. You can now capture the money. After user accepts the requested one-off payment. Reserved Payment successfully reserved. 0
Rejected User rejected one-off payment request in MobilePay. Right after user rejects one-off payment. Rejected Rejected by user. 50001
Expired One-off payment was neither accepted, nor rejected by user. 1 day after you requested one-off payment Expired Expired by system. 50008

One-off payment state diagram

Capture Reserved One-Off Payment

When you receive a callback about successfully reserved payment, now it’s time to capture your money. You can do that by making a call to POST /api/providers/{providerId}/agreements/{agreementId}/oneoffpayments/{paymentId}/capture endpoint. If the HTTP response is 204 - No Content, it means that the money was transfered to your account.

Cancel One-Off Payment Request/Reservation

In case you weren’t able to deliver goods or any other problem occur, you can always cancel one-off payment until it’s not captured or expired. You can do that by making a call to DELETE /api/providers/{providerId}/agreements/{agreementId}/oneoffpayments/{paymentId} endpoint. If the HTTP response is ‘204 - No Content’, it means that one-off payment request/reservation was canceled.

It is mandatory for the merchant to Capture or Cancel one-off payment if it was reserved on a customer account.


Refunds

Full refund - 100% of the amount paid is returned to the payer.If the amount is not specified, the payment will be fully refunded
Partial refund - An amount up to the net (the amount the merchant received) will be returned to the payer. Multiple partial refunds can be made.If the amount is specified, it has to be less than or equal to the amount payed. No refund otherwise. A payment can be refunded partially several times, until the amount is 0 (zero).

MP Subscriptions recurring or one-off payment refund CANNOT be made without original payment. Payment ID must be the same for both actions.

Request a Refund

Use the POST /api/providers/{providerId}/agreements/{agreementId}/payments/{paymentId}/refunds endpoint to request a Refund.

{
    "amount": 10.99,
    "status_callback_url" : "https://example.com",
    "external_id": "ABC123"
}

Request parameters

Parameter Type Required Description Valid values
amount number(0.01) optional The requested amount to be returned. >= 0.01, decimals separated with a dot. If not specified, payment will be fully refunded.
status_callback_url string required Link relation hyperlink reference. https://<merchant’s url>
external_id string optional Refund’s identifier on the merchant’s side. This will be included in the request body of the refund callback.  

The POST /api/providers/{providerId}/agreements/{agreementId}/payments/{paymentId}/refunds service returns HTTP 202 and the response contains single value: a unique id of the newly created Refund.

HTTP 202 Response body example
{
    "id": "263cfe92-9f8e-4829-8b96-14a5e53c9041",
    "amount": 10.99,
    "status_callback_url": "http://example.com",
    "external_id": "ABC123"
}

Callbacks

When the Refund’s status changes from Requested we will do a callback to the callback address provided in request parameter status_callback_url.

Refund callback body example
{
    "refund_id" : "4bb9b33a-f34a-42e7-9143-d6eabd9aae1d",
    "agreement_id" : "1b08e244-4aea-4988-99d6-1bd22c6a5b2c",
    "payment_id" : "c710b883-6ed6-4506-9599-490ead89525a",
    "amount" : "10.99",
    "currency" : "DKK",
    "status" : "Issued",
    "status_text" : null,
    "status_code" : 0,
    "external_id": "ABC123"
}
Refund callback response example
{
    "refund_id" : "4bb9b33a-f34a-42e7-9143-d6eabd9aae1d",
    "agreement_id" : "1b08e244-4aea-4988-99d6-1bd22c6a5b2c",
    "payment_id" : "c710b883-6ed6-4506-9599-490ead89525a",
    "status_code" : "3000",
    "status_text" : "Server is down.",
    "transaction_id" : "63679ab7-cc49-4f75-80a7-86217fc105ea"
}

New Status Condition When to expect Callback status Callback status_text Callback status_code
Issued The Refund was successfully issued Right after the refund request was received Issued    
Declined If Payment is fully refunded Right after the refund was requested Declined Payment is fully refunded. 60001
Declined If the total sum of previous Refunds exceed the original payment amount Right after the refund was requested Declined The total sum of previous Refunds cannot exceed the original payment amount. 60002
Declined When Refund was declined by system Right after the refund was requested Declined Payment was not found. 60003
Declined When Refund was declined by system Right after the refund was requested Declined Payment cannot be refunded. 60004
Declined A catch-all error code when Refund was declined by core system. Right after the refund was requested Declined Refund was declined by system. 60005

Refund screens within mobile application:

Invoices

Add invoice details to subscription payment

You can now add invoice details to your payment. These will be shown to the user in the MobilePay app. Also we will generate a PDF file that will also be accessible to the user from the MobilePay.

All you need to do is attach an invoice object to the property (which is optional) of current payment object.

POST /api/providers/{providerId}/paymentrequests
[
    {
        "agreement_id": "fda31b3c-794e-4148-ac00-77b957a7d47f",
        "amount": "10.99",
        "due_date": "2017-03-09",
        "next_payment_date": "2017-04-09",
        "external_id": "PMT000023",
        "description": "Monthly payment"
        "invoice": {
            "consumer_name": "John Johnson",
            "consumer_phone_number": "+4544667788",
            "total_amount": 10,
            "total_vat_amount": 10,
            "issue_date": "2018-08-22",
            "invoice_number": "58652",
            "order_date": "2018-08-22",
            "due_date": "2018-08-22",
            "consumer_address_lines": [
                "Paradisæblevej 13",
                "CC-1234 Andeby",
                "Wonderland"
            ],
            "invoice_articles": [
                "article_number": "456",
                "article_description": "Lorem ipsum dolor sit amet",
                "vat_rate": 25,
                "total_vat_amount": 25
                "total_price_including_vat": 25,
                "unit": "pcs",
                "quantity": 6,
                "price_per_unit": 60,
                "price_reduction": 1.2,
                "price_discount": 2,
                "bonus": 5
            ],
            "merchant_contact_name": "Some Company",
            "delivery_address_lines": [
                "Østerbrogade 120",
                "CC-1234 Andeb"
            ],
            "payment_reference": "ABCD1234",
            "delivery_date": "2018-08-22",
            "merchant_order_number": "ABCD1234",
            "buyer_order_number": "ABCD1234",
            "comment": "Lorem ipsum dolor sit amet, eros faucibus aliqua erat aliquam odio vitae."
        }
    }
]

Add invoice details to one-off payment on an existing agreement.

You can also add invoice details to a one-off payment. They will be shown to the user in the MobilePay app. Also we will generate a PDF file that will also be accessible to the user from the MobilePay.

All you need to do is attach an invoice object to the property (which is optional) of current one-off payment object.

POST /api/providers/{providerId}/agreements/{agreementId}/oneoffpayments
{
    "amount": "80",
    "external_id": "OOP00348",
    "description": "Pay now for additional goods",
    "links": [
        {
            "rel": "user-redirect",
            "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
        }
    ],
    "invoice": {
        "consumer_name": "John Johnson",
        "consumer_phone_number": "+4544667788",
        "total_amount": 10,
        "total_vat_amount": 10,
        "issue_date": "2018-08-22",
        "invoice_number": "58652",
        "order_date": "2018-08-22",
        "due_date": "2018-08-22",
        "consumer_address_lines": [
            "Paradisæblevej 13",
            "CC-1234 Andeby",
            "Wonderland"
        ],
        "invoice_articles": [
            "article_number": "456",
            "article_description": "Lorem ipsum dolor sit amet",
            "vat_rate": 25,
            "total_vat_amount": 25
            "total_price_including_vat": 25,
            "unit": "pcs",
            "quantity": 6,
            "price_per_unit": 60,
            "price_reduction": 1.2,
            "price_discount": 2,
            "bonus": 5
        ],
        "merchant_contact_name": "Some Company",
        "delivery_address_lines": [
            "Østerbrogade 120",
            "CC-1234 Andeb"
        ],
        "payment_reference": "ABCD1234",
        "delivery_date": "2018-08-22",
        "merchant_order_number": "ABCD1234",
        "buyer_order_number": "ABCD1234",
        "comment": "Lorem ipsum dolor sit amet, eros faucibus aliqua erat aliquam odio vitae."
    }
}

Add invoice details to one-off payment with a new agreement.

You can also add invoice details to a one-off payment when creating a new agreement. They will be shown to the user in the MobilePay app. Also we will generate a PDF file that will also be accessible to the user from the MobilePay.

All you need to do is attach an invoice object to the property one_off_payment (which is optional) of an agreement object.

POST /api/providers/{providerId}/agreements
{
  "external_id": "AGGR00068",
  "amount": "10",
  "currency": "DKK",
  "description": "Monthly subscription",
  "next_payment_date": "2017-03-09",
  "frequency": 12,
  "links": [
    {
      "rel": "user-redirect",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "success-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    },
    {
      "rel": "cancel-callback",
      "href": "https://example.com/1b08e244-4aea-4988-99d6-1bd22c6a5b2c"
    }
  ],
  "country_code": "DK",
  "plan": "Basic",
  "expiration_timeout_minutes": 5,
  "mobile_phone_number": "4511100118",
  "one_off_payment": 
    {
      "amount": "80",
      "external_id": "OOP00348",
      "description": "Down payment for our services",
      "invoice": {
        "consumer_name": "John Johnson",
        "consumer_phone_number": "+4544667788",
        "total_amount": 10,
        "total_vat_amount": 10,
        "issue_date": "2018-08-22",
        "invoice_number": "58652",
        "order_date": "2018-08-22",
        "due_date": "2018-08-22",
        "consumer_address_lines": [
            "Paradisæblevej 13",
            "CC-1234 Andeby",
            "Wonderland"
        ],
        "invoice_articles": [
            "article_number": "456",
            "article_description": "Lorem ipsum dolor sit amet",
            "vat_rate": 25,
            "total_vat_amount": 25
            "total_price_including_vat": 25,
            "unit": "pcs",
            "quantity": 6,
            "price_per_unit": 60,
            "price_reduction": 1.2,
            "price_discount": 2,
            "bonus": 5
        ],
        "merchant_contact_name": "Some Company",
        "delivery_address_lines": [
            "Østerbrogade 120",
            "CC-1234 Andeb"
        ],
        "payment_reference": "ABCD1234",
        "delivery_date": "2018-08-22",
        "merchant_order_number": "ABCD1234",
        "buyer_order_number": "ABCD1234",
        "comment": "Lorem ipsum dolor sit amet, eros faucibus aliqua erat aliquam odio vitae."
    }
  }
}

Invoice object

Parameter Sub Parameter Type Description  
consumer_name   string Required. Full name of the user. We validate it using  
consumer_phone_number   string Required. Mobile phone number of the MobilePay user. Should start with a ‘+’ sign and country phone code.
E.g +4512345678 or +35812345678
 
total_amount   decimal Required. The requested amount to be paid.
>0.00, decimals separated with a dot.
 
total_vat_amount   decimal Required. VAT amount. >0.00, decimals separated with a dot.  
issue_date   date Required. Issue date of invoice. ISO date format: YYYY-MM-DD  
invoice_number   string Required. Invoice number.  
order_date   date Required. Order date of invoice. ISO date format: YYYY-MM-DD  
due_date   date Required. Payment due date. Must be between today and 400 days ahead, otherwise the request will be declined. ISO date format: YYYY-MM-DD  
consumer_address_lines   string[] At least one is required. Address of consumer receiving the invoice.  
invoice_articles   array At least one is required.  
  article_number string Required. Article Number, e.g. 123456ABC  
  article_description string Required. Article Description.  
  vat_rate decimal Required. VAT Rate of article.  
  total_vat_amount decimal Required. Total VAT amount of article.  
  total_price_including_vat decimal Required. Total price of article including VAT.  
  unit string Required. Unit, e.g. Pcs, Coli.  
  quantity decimal Required. Quantity of article.  
  price_per_unit decimal Required. Price per unit.  
  price_reduction decimal Price reduction.  
  price_discount decimal Price discount.  
  bonus decimal Bonus of article.  
merchant_contact_name   string Contact name for the individual who issued the invoice.  
delivery_address_lines   string[] Delivery address.  
payment_reference   string(60) Reference used on the payment to do reconciliation. If not filled, invoice number will be used as reference.  
delivery_date   date Delivery date of invoice. ISO date format: YYYY-MM-DD  
merchant_order_number   string The merchant order number for the invoice used internally by the merchant.  
buyer_order_number   string The buyer order number for the invoice used externally by the merchant.  
comment   string Additional information to the consumer.  

Note: All decimal values should be >0 and decimals (no more than 2 digits) should be separated with a dot.

PDF invoice examples

These are the examples of how your data will look like to user in the MobilePay, when it is generated to PDF file.

Danish example:

Finnish example: