Mobile SDK

Merchant Backend V3

To use the Swedbank Pay Mobile SDK, you must have a backend server that communicates with your Configuration. One way to start developing is to use the Merchant Backend API.

Edit "Merchant Backend V3" on GitHub

The Merchant Backend API serves as a simple starting point, and an illustrative example of how to integrate the SDK to your backend systems. The SDK has a Configuration implementation for a backend implementing this API; in addition, there is both a Node.js and a Java sample implementation of this API available.

Even if you plan to integrate the SDK using your own backend API, it is recommended to read through this chapter; especially the section Payment Url Helper Endpoints, which will illustrate how any paymentUrl created for the SDK should behave.

The Mobile SDK Merchant Backend API contains a total of six 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.

The Merchant Backend Configuration

To use a backend implementing the Merchant Backend API, you can use the Merchant Backend Configuration provided with the SDK. This implementation is available as SwedbankPaySDK.MerchantBackendConfiguration on iOS and com.swedbankpay.mobilesdk.merchantbackend.MerchantBackendConfiguration on Android; on Android you create the MerchantBackendConfiguration object via a MerchantBackendConfiguration.Builder.

At a minimum, you must supply the url of the Merchant Backend, i.e. the url of the Root Endpoint. On iOS, you must also have registered a URL type for the SDK: that URL type must have a single scheme, and an additional property with name com.swedbank.SwedbankPaySDK.callback, type Boolean, and value YES. Alternatively you may set the url scheme explicitly in the initializer. Refer to the class documentation for more options.

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
HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorders": "/swedbank-pay-mobile/paymentorders"
}
Field Type Description
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.

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.

Optionally, if your implementation uses instrument mode payments, your backend can return the list of valid instruments, along with an endpoint to change the instrument. If you do this, you must also implement the Change Instrument endpoint. The Merchant Backend Configuration on the client side can then use this endpoint to change the instrument of an ongoing payment order.

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-checkout 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": { }
}

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&_tc_tid=30f2168171e142d38bcd4af2c3721959",
            "rel": "view-checkout",
            "method": "GET",
            "contentType": "application/javascript"
        }
    ]
}

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

If instrument mode is used, an you wish to be able to change the instrument, you can provide the list of valid instruments.

Patching The Payment Order

To modify the payment order you perform a patch operation. If instrument mode is used, you change the instrument by patching the payment with the SetInstrument operation. The SDK handles this by packaging the id of the PaymentOrder with the values needed to perform the operation, and sends it to the patch endpoint of the Merchant Backend. The Backend will then need to validate the request, and then passing it on to SwedbankPay as a PATCH request to execute the functionality. The response of that request is passed back to the SDK.

This makes all operations behave the same and the backend does not need to communicate or setup special endpoints for each operation, e.g. the abort operation is handled the same way. This paves the way for future operations, which will also be handled like this.

You only need to implement this endpoint if you are using instrument mode payments, or one of the other operations.

Request

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

{
    "href": "https://api.externalintegration.payex.com/psp/paymentorders/6290caac-90f6-4f10-bb90-08da37ab87d7"
    "paymentorder": {
        "operation": "SetInstrument",
        "instrument": "CreditCard"
    }
}
Required Field Type Description
check href string The href of the Operation
check paymentOrder object The changes to make to the payment order
check operation string The operation to perform: SetInstrument
check instrument string The instrument to set

Merchant Backend will then make a corresponding request to the Swedbank Pay API.

Forwarded Request

1
2
3
4
5
6
7
8
9
10
11
PATCH https://api.externalintegration.payex.com/psp/paymentorders/6290caac-90f6-4f10-bb90-08da37ab87d7 HTTP/1.1
Host: api.externalintegration.payex.com
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "paymentorder": {
        "operation": "SetInstrument",
        "instrument": "CreditCard"
    }
}

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&_tc_tid=30f2168171e142d38bcd4af2c3721959",
            "rel": "view-checkout",
            "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 behavior 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 with an html document that attempts to immediately redirect to 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. The html document shall also contain a link to that same url. This is needed because in some cases the browser will block the redirect to an Intent-scheme url, and will instead require that the navigation to that url happen from a user interaction.

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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HTTP/1.1 200 OK
Content-Type: text/html

<html>
<head>
<title>Swedbank Pay Payment</title>
<link rel="stylesheet" href="https://design.swedbankpay.com/v/4.3.0/styles/dg-style.css">
<meta name="viewport" content="width=device-width">
<meta http-equiv="refresh" content="0;url=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; ①">
</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="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;">Back to app</a></p>
</div>
</body>
</html>
  • ① 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

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 available in the production environment.]

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 universal 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://ecom.stage.payex.com/externalresourcehost/trampoline?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 in the production environment. The url will be updated when it is released.], but you can also host the back-link page yourself if desired.

Safari will immediately follow the redirect:

Request

1
2
GET /externalresourcehost/trampoline?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: ecom.stage.payex.com
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
17
18
19
20
21
22
23
24
25
26
HTTP/1.1 200 OK
Content-Type: text/html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Swedbank Pay Redirect</title>
    <link rel="icon" type="image/png" href="/externalresourcehost/content/images/favicon.png">
    <link rel="stylesheet" href="/externalresourcehost/content/css/style.css">
</head>
<body>
    <div class="trampoline-container" onclick="redirect()">
    <img alt="Swedbank Pay Logo" src="/externalresourcehost/content/images/swedbank-pay-logo-vertical.png" />
    <span class="trampoline-text">
            <a>Back to Your Ecom App</a>
    </span>
</div>

<script>
    function redirect() { window.location.href = decodeURLComponent("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"); };
</script>

</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 behavior 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 perhaps a more appropriate status. This may be changed in the future, after testing that the routing works correctly with that status.

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