Mobile SDK

Merchant Backend

schedule 20 min read

To use the Swedbank Pay Mobile SDK, you must have a backend server hosting the Mobile SDK API.

warning

Unsupported

The SDK is at an early stage of development and is not supported as of yet by Swedbank Pay. It is provided as a convenience to speed up your development, so please feel free to play around. However, if you need support, please wait for a future, stable release.

The Mobile SDK Merchant Backend API contains a total of five endpoints, three of which have statically defined paths. An OpenAPI specification is available. (It may be easier to view it in the Swagger Editor.)

The main part of the API is designed as a transparent wrapper around the Swedbank Pay API, which is the same one used in Checkout. Additionally, two “helper” endpoints are specified, which facilitate the proper routing of the Payment Url back to the originating app.

Authentication and Authorization

You should have some authorization and authentication measures in place to prevent misuse of your Merchant Backend API. The sample implementations have a very rudimentary API key header check. This may or may not be sufficient to your purposes. You should adapt the sample implementation or create your own according to your security needs.

The mobile component of the SDK allows adding your own headers to the requests it makes. Therefore you can build your own authentication and authorization measures by adding custom headers in the app, and checking that they have the correct content in the backend.

Root Endpoint

The root endpoint is used to discover the main API endpoints. The URL of the root endpoint is what is configured as the “Backend URL” in the mobile SDK component. The point of this is to not bind your service to any particular path or even domain. In most cases, however, you can serve a static response for the root endpoint, with the other endpoint urls being relative to the root endpoint. The sample implementations do this.

Request

1
2
3
GET /swedbank-pay-mobile/ HTTP/1.1
Host: example.com
Your-Api-Key: secretish

Response

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Content-Type: application/json

{
    "consumers": "/swedbank-pay-mobile/consumers",
    "paymentorders": "/swedbank-pay-mobile/paymentorders"
}
Field Type Description
consumers string URL of the “consumers” endpoint. Resolved against the root endpoint URL.
paymentorders string URL of the “paymentorders” endpoint. Resolved against the root endpoint URL.

N.B! The API as specified allows assigning endpoints to hosts other that the root endpoint host. However, as this seen to be an uncommon use case, the mobile component of the SDK is, by default, configured to only accept links to the domain of the root endpoint, or its subdomains. If your configuration uses other hosts, you must manually allow them in your mobile app’s configuration.

Consumers Endpoint

The consumers endpoint is used to start a consumer identification session. It is specified as a transparent wrapper around the corresponding Swedbank Pay API. The sample implementations do superficial input validation, and forward the request to the Swedbank Pay API without further processing. You are free to override this default behaviour as you see fit in your implementation, but the default should be fine for most use-cases. The expected response is the same as the expected response to the Swedbank Pay API. The default is to pass the response from Swedbank as-is; you should probably not modify this behaviour. Specifically, the response must contain the view-consumer-identification operation.

Request

1
2
3
4
5
6
7
8
9
10
POST /swedbank-pay-mobile/consumers HTTP/1.1
Host: example.com
Your-Api-Key: secretish
Content-Type: application/json

{
    "operation": "initiate-consumer-session",
    "language": "sv-SE",
    "shippingAddressRestrictedToCountryCodes" : ["NO", "SE", "DK"]
}
Required Field Type Description
check operation string initiate-consumer-session, the operation to perform.
check language string Selected language to be used in Checkin. Supported values are sv-SE, nb-NO or en-US.
check shippingAddressRestrictedToCountryCodes string List of supported shipping countries for merchant. Using ISO-3166 standard.

At this point, the Merchant Backend will make a corresponding request to the Swedbank Pay API, using its secret access token.

Forwarded Request

1
2
3
4
5
6
7
8
9
10
POST /psp/consumers HTTP/1.1
Host: api.externalintegration.payex.com
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "operation": "initiate-consumer-session",
    "language": "sv-SE",
    "shippingAddressRestrictedToCountryCodes" : ["NO", "SE", "DK"]
}

The Merchant Backend will then forward the response it received back to the calling app.

Response & Forwarded Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
HTTP/1.1 200 OK
Content-Type: application/json

{
    "token": "7e380fbb3196ea76cc45814c1d99d59b66db918ce2131b61f585645eff364871",
    "operations": [
        {
            "method": "GET",
            "rel": "redirect-consumer-identification",
            "href": "https://ecom.externalintegration.payex.com/consumers/sessions/7e380fbb3196ea76cc45814c1d99d59b66db918ce2131b61f585645eff364871",
            "contentType": "text/html"
        },
        {
            "method": "GET",
            "rel": "view-consumer-identification",
            "href": "https://ecom.externalintegration.payex.com/consumers/core/scripts/client/px.consumer.client.js?token=5a17c24e-d459-4567-bbad-aa0f17a76119",
            "contentType": "application/javascript"
        }
    ]
}
Field Type Description
token string A session token used to initiate Checkout UI.
operations array The array of operation objects to choose from, described in detail in the table below.
└➔ rel string The relational name of the operation, used as a programmatic identifier to find the correct operation given the current state of the application.
└➔ method string The HTTP method to use when performing the operation.
└➔ contentType string The HTTP content type of the target URI. Indicates what sort of resource is to be found at the URI, how it is expected to be used and behave.
└➔ href string The target URI of the operation.

Payment Orders Endpoint

The paymentorders endpoint is used to create a new Payment Order. It is specified as a transparent wrapper around the corresponding Swedbank Pay API. However, it is to be expected that your backend will need to process the payment order both before making the Swedbank Pay API call, and after receiving the response from Swedbank Pay. The sample implementations validate the input, then create an internal unique identitifer for the payment order, and set that as paymentorder.payeeInfo.payeeReference, before making the Swedbank Pay call. After receiving the response, the backend stores the id of the Payment Order for future use, and forwards the response to the SDK.

A production implementation should validate the payment order also from a business logic perspective. This is, naturally, outside the scope of the SDK, as is any other processing you may wish to perform with the payment order. The SDK expects the same form of response as returned from the Swedbank Pay API. Specifically, the response must contain the view-paymentorder operation.

Request

1
2
3
4
5
6
7
8
POST /swedbank-pay-mobile/paymentorders HTTP/1.1
Host: example.com
Your-Api-Key: secretish
Content-Type: application/json

{
    "paymentorder": { "①": "" }
}
Required Field Type Description
check paymentorder object The payment order to create

At this point, the Merchant Backend will preform necessary processing, and make a corresponding request to the Swedbank Pay API, using its secret access token.

Forwarded Request

1
2
3
4
5
6
7
8
POST /psp/paymentorders HTTP/1.1
Host: api.externalintegration.payex.com
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "paymentorder": { }
}

The Merchant Backend will then forward the response it received back to the calling app.

Response & Forwarded Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HTTP/1.1 201 Created
Content-Type: application/json

{
    "paymentorder": {
      "id": "/psp/paymentorders/09ccd29a-7c4f-4752-9396-12100cbfecce"
    },
    "operations": [
        {
            "href": "https://ecom.externalintegration.payex.com/paymentmenu/core/scripts/client/px.paymentmenu.client.js?token=5a17c24e-d459-4567-bbad-aa0f17a76119&culture=sv-SE",
            "rel": "view-paymentorder",
            "method": "GET",
            "contentType": "application/javascript"
        }
    ]
}

Payment Url Helper Endpoints

The Payment Url helper endpoints do not interact directly with Swedbank Pay. Instead, they are used to route any navigations to the payment order’s payment url to the app using the SDK.

The payment url allows navigations to third-party sites to happen as a part of the payment process. To continue the payment after any third-party processes, navigating to the payment url is expected to load the payment menu again. In the case of an app using the SDK, this means that the payment url must be routed to that app, and the app must react to that url by reloading the payment menu. Furthermore, for maximum compatibility, the payment url should be a regular https url.

Since we want the payment urls to be https urls, they must be hosted somewhere. These helper endpoints facilitate that. Each platform has its own payment url helper, due to the platforms’ different requirements for url routing. The endpoints take query arguments to enable apps using the SDK to locally generate unique payment urls for each payment order. The endpoints have no side-effects, and will always return the same response for the same query arguments.

The payment url helper endpoints are specified with static paths relative to the root endpoint url. This is done so that payment urls can be generated locally on the app, without needing to make a network round trip at that point. The SDK has no hard requirement for the helper endpoint urls to have such a relationship to the root endpoint url, but it does contain utility methods for easier integration when that is the case. If you wish to host the payment url helper endpoints elsewhere, or, indeed, replicate the behaviour with some other schema for the payment urls, you must manually set paymentorder.urls.paymentUrl to the correct value when creating your payment orders.

Importantly, the payment url helper endpoints must be accessible without any authentication headers. This is because the scenario where they will be used is when a third-party site wishes to navigate back to the payment order. Such a site will necessarily not have any authentication tokens related to your backend. Consequently, it is important to ensure that these endpoints do not inadvertently disclose information.

The sample implementations serve these payment url helper endpoints at the specified static paths.

N.B! The SDK generates unique payment urls by adding unique query arguments to the helper endpoint url. These payment urls only have meaning on the generating device, in the generating app. Opening them on another device will be unable to navigate the user to the originating payment menu.

Android Payment Url Helper

The Android payment url helper endpoint expects a query parameter named package: the package name of the Android application to redirect to. It has no requirements as to the existence or value of other query parameters. As the application using the SDK knows its own package name, it can use this endpoint to generate a payment url that is routed back to itself.

The specified path for the Android payment url helper endpoint is sdk-callback/android-intent. The default constructors of the Android SDK form payment urls by appending sdk-callback/android-intent to the backend url, i.e. the root endpoint, and adding the package query parameter with the containing application’s package name, and an id query parameter with a random value.

The endpoint responds to a correct request with a redirect response, the redirect location being an Intent-scheme Url. That url is constructed such that it uses the value of the package query parameter as the target package of the intent. The action of the intent shall be com.swedbankpay.mobilesdk.VIEW_PAYMENTORDER; the SDK has an intent filter for this action. The uri (data) of the intent shall be the full url used in the request: if the endpoint was requested with the url.

Request

1
2
GET /swedbank-pay-mobile/sdk-callback/android-intent?package=your.ecom.app&id=abb50c53-53c1-4138-923f-59fcf0acd08d HTTP/1.1
Host: example.com
Required Field Type Description
check package string The package name of the Android application to redirect to

Response

1
2
HTTP/1.1 301 Moved Permanently ①
Location: intent://example.com/swedbank-pay-mobile/sdk-callback/android-intent?package=your.ecom.app&id=abb50c53-53c1-4138-923f-59fcf0acd08d#Intent;scheme=https;action=com.swedbankpay.mobilesdk.VIEW_PAYMENTORDER;package=your.ecom.app;end; ②
  • ① 302 Found is perhaps a more appropriate status. This may be changed in the future, after testing that the routing works correctly with that status.
  • ② The intent url is transformed to an Android Intent using the data after the #Intent; token. The uri of that intent is the intent url up to that token, with the intent scheme replaced according to the scheme= parameter – in this case https.

Using a payment url crafted this way causes an intent with the payment url to be delivered to the application when a third-party page navigates to the payment url. The SDK receives this intent, recognizes the payment url, and reloads the payment menu.

N.B! It is possible to craft arbitrary com.swedbankpay.mobilesdk.VIEW_PAYMENTORDER intents using this endpoint. However, further processing of such intents is dependent on local data, and thus this endpoint leaks no information. Indeed, it is conceptually possible for two different devices to use the same payment url to refer to different payments. Your implementation may restrict the requests it serves; e.g. you may only allow a specific package.

iOS Payment Url Helper

Background

The iOS payment url helper endpoint is more involved than the Android one. While a similar mechanism could be used with custom url schemes, doing so will not provide optimal user experience: custom schemes will show a confirmation dialog before being routed to the handling application, and the content of that dialog is not under developer control. Instead, the best practice for assigning urls to applications is to use Universal Links.

With the merchant backend host and the iOS application using the SDK configured correctly, the payment url becomes a universal link. Universal links function such that they are given directly to the handling application. This means that if the navigation to the payment url is handled as a unversal link, the actual payment url is never dereferenced before being handled by the application. In this scenario, is does not matter what kind of response would be received by making a GET request to the payment url. Unfortunately, this is not guaranteed to happen.

As documented, universal links open the registered application “when [the user] tap[s] links to your website within Safari”, but “When a user browses your website in Safari and taps a universal link in the same domain, the system opens that link in Safari – If the user taps a universal link in a different domain, the system opens the link in your app.” This presents two preconditions: the navigation must originate from user interaction, and the domain of the universal link must be different to the domain of the current page. Also, practice has shown that universal links may still sometimes fail to work as intended, so we must have some way of escaping that situation.

In order to have a foolproof system with optimal user experience, we must therefore work correctly in different scenarios:

  1. The initial navigation to the payment url is opened in the application: no requirements for the payment url
  2. The initial navigation to the payment url is opened in Safari: need a way to link back to the payment url such that it is opened in the application instead
    • 2a: The second navigation to the payment url is opened in the application: no further requirements for the payment url
    • 2b: The second navigation to the payment url is also opened in Safari: out of nice-UX options; need to redirect to a custom scheme url

This state of matters necessitates an unintuitive and cumbersome system involving two hosts and a custom url scheme. The usage of two hosts is unavoidable if maximum compatibility combined with optimum user experience is desired. The custom url scheme is unavoidable if an escape hatch in badly behaving scenarios is desired. However, universal links need be configured only to one of the involved hosts, namely the one hosting the payment url. Thus, the page with a link back to the payment url can be on a generic server hosted by Swedbank Pay. [Development note: the Swedbank Pay server for this purpose is not yet publicly available.]

iOS Payment Url System

The iOS payment url helper endpoint expects the following query parameters:

  • scheme: The custom scheme for Swedbank Pay SDK payment urls in the application
  • language: The language to use in the back-link web page in the case 2 above

The endpoint also accepts two optional query parameters:

  • app: The name of the application to show in the back-link web page
  • fallback: If true, redirects to a custom-scheme url instead of the back-link web page

Like the Android payment url helper endpoint, the iOS payment url helper endpoint imposes no requirements on any other query parameters.

The specified path for the iOS payment url helper endpoint is sdk-callback/ios-universal-link. The default constructors of the iOS SDK form payment urls by appending sdk-callback/ios-universal-link to the backend url, i.e. the root endpoint, and adding the scheme query parameter with the custom scheme registered in the app for handling Swedbank Pay SDK payment urls, the language parameter with the chosen language, the app parameter with the application name (if available), and an id query parameter with a random value. The fallback parameter is not set for the payment url.

Let us consider the cases above, when a third-party page wants to navigate back to the payment menu. Case 1 requires no further analysis. The univeral link system works as we intend, the payment url is opened in the app as-is.

Case 2 causes the payment url to be opened in Safari. In this case we want to show a web page with a link back to the payment url, so the user can tap the link and it will be opened in the application, as provided by the conditions outlined above. Since this page must be served from a different domain, the payment url itself must respond with a redirect response.

Request

1
2
GET /swedbank-pay-mobile/sdk-callback/ios-universal-link?scheme=yourecomapp&language=en-US&id=abb50c53-53c1-4138-923f-59fcf0acd08d&app=Your%20Ecom%20App HTTP/1.1
Host: example.com
Required Field Type Description
check scheme string The custom scheme for handling Swedbank Pay payment urls in the app
check language string The language to use in the back-link page
  app string The application name to display in the back-link page
  fallback boolean If true, redirect to custom scheme rather than back-link page

Response

1
2
HTTP/1.1 301 Moved Permanently ①
Location: https://payment.url.trampoline.host/payment/url/trampoline/path?target=https%3A%2F%2Fexample.com%2Fswedbank-pay-mobile%2Fsdk-callback%2Fios-universal-link%3Fscheme%3Dyourecomapp%26language%3Den-US%26id%3Dabb50c53-53c1-4138-923f-59fcf0acd08d%26app%3DYour%2520Ecom%2520App%26fallback%3Dtrue&language=en-US&app=Your%20Ecom%20App

This example uses the public server hosted by Swedbank Pay [Development note: The public server is not yet available. The authority and path of url will be updated reflect the correct values for the public server when available.], but you can also host the back-link page yourself if desired.

Safari will immediately follow the redirect:

Request

1
2
GET /payment/url/trampoline/path?target=https%3A%2F%2Fexample.com%2Fswedbank-pay-mobile%2Fsdk-callback%2Fios-universal-link%3Fscheme%3Dyourecomapp%26language%3Den-US%26id%3Dabb50c53-53c1-4138-923f-59fcf0acd08d%26app%3DYour%2520Ecom%2520App%26fallback%3Dtrue&language=en-US&app=Your%20Ecom%20App HTTP/1.1
Host: payment.url.trampoline.host
Required Field Type Description
check target string The link to open when the button on the page is tapped
check language string The language to use in the page
  app string The application name to display in the page

Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HTTP/1.1 200 OK
Content-Type: text/html

<html>
<head>
<title>Your Ecom App Payment by Swedbank Pay</title>
<link rel="stylesheet" href="https://design.swedbankpay.com/v/4.3.0/styles/dg-style.css">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div class="text-center">
<img src="https://design.swedbankpay.com/v/4.3.0/img/swedbankpay-logo.svg" alt="Swedbank Pay" height="120">
<p><a class="btn btn-executive" href="https://example.com/swedbank-pay-mobile/sdk-callback/ios-universal-link?scheme=yourecomapp&language=en-US&id=abb50c53-53c1-4138-923f-59fcf0acd08d&app=Your%20Ecom%20App&fallback=true">Back to Your Ecom App</a></p>
</div>
</body>
</html>

The back-link page contains a link to the payment url, but with an added with the fallback=true parameter. In case 2a the link will be opened in the application, and we are done. In case 2b, however, the link is again opened in Safari. Since the back-link page did not work, it makes no sense to redirect back to it again. Instead we will redirect to a custom scheme url, as those will always be opened in the registered application, albeit only after a confirmation dialog. Of course, this means that we need to know that the payment url is being opened from the back-link page. The fallback=true parameter signals to the iOS payment url helper endpoint to alter its behaviour this way.

You may note that in case 2a the application was not opened with the original payment url, but with one with an extra query parameter. The SDK handles this by considering the query part of the payment url separately, allowing additional parameters.

Case 2b continues by making a request to the payment url with the added fallback=true parameter. The endpoint responds with a redirect similar to the Android one: the scheme is replaced with the custom scheme, and the rest of the request url is unmodified.

Request

1
2
GET /swedbank-pay-mobile/sdk-callback/ios-universal-link?scheme=yourecomapp&language=en-US&id=abb50c53-53c1-4138-923f-59fcf0acd08d&app=Your%20Ecom%20App&fallback=true HTTP/1.1
Host: example.com

Response

1
2
HTTP/1.1 301 Moved Permanently ①
Location: yourecomapp://example.com/swedbank-pay-mobile/sdk-callback/ios-universal-link?scheme=yourecomapp&language=en-US&id=abb50c53-53c1-4138-923f-59fcf0acd08d&app=Your%20Ecom%20App&fallback=true

Note that this custom-scheme link is otherwise equal to the universal link opened in case 2a; accordingly, the SDK handles this by allowing the scheme of the payment url to be either the original scheme, or the custom scheme registered to the application.

  • ① 302 Found is again a more appropriate status. This may be changed in the future.

Apple App Site Association

The iOS payment url helper endpoint must be configured as a universal link to the application for it to work correctly. Doing this requires an Apple app site association file on the host of the iOS payment url. This file must be at a path relative to the host root (namely /.well-known/apple-app-site-association), and is thus outside the scope of, but linked to, the merchant backend API.

The example implementations assume they are rooted at host root, and serve an Apple app site association using a configurable application ID.

Request

1
2
GET /.well-known/apple-app-site-association HTTP/1.1
Host: example.com

Response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Content-Type: application/json

{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID":"YOURTEAMID.your.ecom.app",
                "paths":["/swedbank-pay-mobile/sdk-callback/*"]
            }
        ]
    }
}

Problems

If there are any errors in servicing a request, they should be reported using Problem Details for HTTP APIs (RFC 7807) messages, like the Swedbank Pay APIs do. In particular, if the Swedbank Pay API response contains a problem, that problem should be forwarded to the client making the original request.

Merchant Backend Problems

The following problem types are defined for Merchant Backend specific errors. The mobile SDK components contain data types for easy processing of these error types. The sample implementations emit these errors in the specified circumstances; your own implementation is encouraged to do so as well.

All these Merchant Backend problem types will have a URI in the format https://api.payex.com/psp/errordetail/mobilesdk/<error-type>.

Type Status Description
gatewaytimeout 504 The Swedbank Pay API did not respond in time.
badgateway 502 The Merchant Backend did not understand the response from the Swedbank Pay API.
unauthorized 401 The request did not have proper credentials to perform the operation.
badrequest 400 The Merchant Backend did not undestand the request.

Your implementation is encouraged to define its own problem types for any domain-specific errors; you should namespace those problem types under a domain name under your control – usually the host name of the Merchant Backend.