Introduction

Introduction

schedule 15 min read

Read on to learn about the fundamentals and common architectural principles of the Swedbank Pay API Platform.

Edit "Introduction" on GitHub

Foundation

The Swedbank Pay API Platform is built using the REST architectural style and the request and responses come in the JSON format. The API has predictable, resource-oriented URIs and use default HTTP features, like HTTP authentication (using OAuth 2), HTTP methods and headers. These techniques are widely used and understood by most HTTP client libraries.

Connection and Protocol

All requests towards Swedbank Pay API Platform are made with HTTP/1.1 over a secure a TLS 1.2 (or higher) connection. Older HTTP clients running on older operating systems and frameworks might receive connection errors when connecting to Swedbank Pay’s APIs. This is most likely due to the connection being made from the client with TLS 1.0 or even SSL, which are all insecure and deprecated. If such is the case, ensure that you are able to connect over a TLS 1.2 connection by reading information regarding your programming languages and environments (Java, PHP Curl, PHP Zend, Ruby, Python, Node.js Request).

You can inspect Swedbank Pay’s TLS and cipher suite support at SSL Labs. Support for HTTP/2 in our APIs is being investigated.

Postel’s Robustness Principle

We encourage you to keep Postel’s robustness principle in mind. Build your integration in a way that is resilient to change, wherever it may come. Don’t confine yourself to the limits of our current documentation examples. A string looking like a guid must still be handled and stored like a string, not as a guid, as it could be a URI in the future. The day our transactionNumber ticks past 1,000,000, make sure your integration can handle number 1,000,001. If some fields, operations or headers can’t be understood, you must be able to ignore them. We have built our requests in a way which allows the payeeInfo field to be placed before metadata, or vice versa if you want. We don’t expect a specific order of elements, so we ask that you shouldn’t either.

Headers

All requests against the API Platform should have a few common headers:

HTTP request

1
2
3
4
5
6
POST /some/resource HTTP/1.1
Content-Type: application/json; charset=utf-8
Accept: application/problem+json; q=1.0, application/json; q=0.9
Authorization: "Bearer 123456781234123412341234567890AB"
Session-Id: 779da454399742248f2942bb064c4707
Forwarded: for=82.115.151.177; host=example.com; proto=https
Required Header Description
check Content-Type The content type of the body of the HTTP request. Usually set to application/json.
check Accept The content type accepted by the client. Usually set to application/json and application/problem+json so both regular responses as well as errors can be received properly.
check Authorization The OAuth 2 Access Token is generated in Swedbank Pay Admin.
  Session-Id A trace identifier used to trace calls through the API Platform (ref RFC 7329). Each request must mint a new GUID/UUID. If no Session-Id is provided, Swedbank Pay will generate one for the request.
  Forwarded The IP address of the payer as well as the host and protocol of the payer-facing web page. When the header is present, only the for parameter containing the payer’s IP address is required, the other parameters are optional. See RFC 7239 for details.

URI Usage

The base URIs of the API Platform are:

Environment Base URL
Test https://api.externalintegration.payex.com/
Production https://api.payex.com/

An important part of REST is its use of hypermedia. Instead of having to perform complex state management and hard coding URIs and the availability of different operations in the client, this task is moved to the server. The client simply follows links and performs operations provided by the API, given the current state of the resource. The server controls the state and lets the client know through hypermedia what’s possible in the current state of the resource. To get an introduction to hypermedia, please watch this 20 minute video.

warning

Don’t build URIs

It is very important that only the base URIs of Swedbank Pay’s APIs are stored in your system. All other URIs are returned dynamically in the response. Swedbank Pay cannot guarantee that your implementation will remain working if you store any other URIs in your system. When performing requests, please make sure to use the complete URIs that are returned in the response. Do not attempt to parse or build upon the returned data – you should not put any special significance to the information you might glean from an URI. URIs should be treated as opaque identifiers you can use to retrieve the identified resource – nothing more, nothing less. If you don’t follow this advice, your integration most assuredly will break when Swedbank Pay makes updates in the future.

Storing URIs

link

Storing URIs

In general, URIs should be discovered in responses to previous requets, not stored.

However, URIs that are used to create new resources can be stored or hard coded. Also, the URI of the generated resource can be stored on your end to GET it at a later point. Note that the URIs should be stored as opaque identifiers and should not be parsed or interpreted in any way.

warning

Operation URIs

URIs that are returned as part of the operations in each response should not be stored.

See the abbreviated example below where psp/creditcard/payments from the POST header is an example of the URI that can be stored, as it is used to create a new resource. Also, the /psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1 URI can be stored in order to retrieve the created payment with an HTTP GET request later.

The URIs found within operations such as the href of update-payment-abort, https://api.externalintegration.payex.com/psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1 should not be stored.

In order to find which operations you can perform on a resource and the URI of the operation to perform, you need to retrieve the resource with an HTTP GET request first and then find the operation in question within the operations field.

Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST /psp/creditcard/payments HTTP/1.1
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "payment": {
        "operation": "Purchase",
        "intent": "Authorization",
        "currency": "SEK",
        "prices": [{
                "type": "CreditCard",
                "amount": 1500,
                "vatAmount": 0
            }
        ],
        "description": "Test Purchase",
        "generatePaymentToken": false,
        "generateRecurrenceToken": false,
        "userAgent": "Mozilla/5.0...",
        "language": "nb-NO",
     }
 }

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
27
28
29
30
31
32
33
34
35
HTTP/1.1 200 OK
Content-Type: application/json

{
    "payment": {
        "id": "/psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1",
        "number": 1234567890,
        "instrument": "CreditCard",
        "created": "2016-09-14T13:21:29.3182115Z",
        "updated": "2016-09-14T13:21:57.6627579Z",
        "state": "Ready",
        "operation": "Purchase",
        "intent": "Authorization",
        },
    "operations": [
        {
            "rel": "update-payment-abort",
            "href": "https://api.externalintegration.payex.com/psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1",
            "method": "PATCH",
            "contentType": "application/json"
        },
        {
            "rel": "redirect-authorization",
            "href": "https://ecom.externalintegration.payex.com/creditcard/payments/authorize/5a17c24e-d459-4567-bbad-aa0f17a76119",
            "method": "GET",
            "contentType": "text/html"
        },
        {
            "rel": "view-authorization",
            "href": "https://ecom.externalintegration.payex.com/creditcard/core/scripts/client/px.creditcard.client.js?token=5a17c24e-d459-4567-bbad-aa0f17a76119",
            "method": "GET",
            "contentType": "application/javascript"
        }
    ]
}

Uniform Responses

When a POST or PATCH request is performed, the whole target resource representation is returned in the response, as when performing a GET request on the resource URI. This is an economic approach that limits the number of necessary GET requests.

Expansion

The payment resource contain the ID of related sub-resources in its response properties. These sub-resources can be expanded inline by using the request parameter expand. This is an effective way to limit the number of necessary calls to the API, as you return several properties related to a Payment resource in a single request.

Note that the expand parameter is available to all API requests but only applies to the request response. This means that you can use the expand parameter on a POST or PATCHrequest to get a response containing the target resource including expanded properties.

This example below add the urls and authorizations field inlines to the response, enabling you to access information from these sub-resources.

HTTP request with expansion

1
2
GET /psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1?$expand=urls,authorizations HTTP/1.1
Host: api.externalintegration.payex.com

To avoid unnecessary overhead, you should only expand the nodes you need info about.

Data Types

Some datatypes, like currency, dates and amounts, are managed in a coherent manner across the entire API Platform.

Currency

All currencies are expressed according to the ISO 4217 standard, e.g SEK, EUR, NOK.

Dates

All dates are expressed according to the ISO 8601 standard that combine dates, time and timezone data into a string, e.g. 2018-09-14T13:21:57.6627579Z.

Locale

When defining locale, we use the combination of language and country codes, e.g. nb-NO, sv-SE, en-US.

Monetary Amounts

All monetary amounts are entered in the lowest momentary units of the selected currency. The amount of SEK and NOK are in ören/ører, and EUR is in cents. Another way to put it is that the code amount is expressed as if the true amount is multiplied by 100.

True amount Code amount
NOK 100.00 10000
SEK 50.00 5000
€ 10.00 1000

Operations

When a resource is created and during its lifetime, it will have a set of operations that can be performed on it. Which operations that are available in a given state varies depending on payment instrument used, what the access token is authorized to do, etc. A subset of possible operations are described below. Visit the technical reference page of a payment instrument for instrument specific operations.

JSON with Operations

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
{
    "payment": {},
    "operations": [
        {
            "href": "http://api.externalintegration.payex.com/psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1",
            "rel": "update-payment-abort",
            "method": "PATCH"
        },
        {
            "href": "https://ecom.externalintegration.payex.com/creditcard/payments/authorize/5a17c24e-d459-4567-bbad-aa0f17a76119",
            "rel": "redirect-authorization",
            "method": "GET"
        },
        {
            "href": "https://ecom.externalintegration.payex.com/swish/core/scripts/client/px.swish.client.js?token=5a17c24e-d459-4567-bbad-aa0f17a76119",
            "rel": "view-payment",
            "method": "GET",
            "contentType": "application/javascript"
        },
        {
            "href": "https://api.externalintegration.payex.com/psp/creditcard/payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/captures",
            "rel": "create-capture",
            "method": "POST"
        }
    ]
}
Field Description
href The target URI to perform the operation against.
rel The name of the relation the operation has to the current resource.
method The HTTP method to use when performing the operation.

The operations should be performed as described in each response and not as described here in the documentation. Always use the href and method as specified in the response by finding the appropriate operation based on its rel value.

Payee Reference

The payeeReference given when creating transactions and payments has some specific processing rules depending on specifications in the contract.

  • It must be unique for every operation, used to ensure exactly-once delivery of a transactional operation from the merchant system.
  • Its length and content validation is dependent on whether the transaction.number or the payeeReference is sent to the acquirer.
    1. If you select Option A in the settlement process (Swedbank Pay will handle the settlement), Swedbank Pay will send the transaction.number to the acquirer and the payeeReference must be in the format of characters A-Za-z0-9 (including -) and string(30).
    2. If you select Option B in the settlement process (you will handle the settlement yourself), Swedbank Pay will send the payeeReference to the acquirer and it will be limited to the format of string(12) and all characters must be digits.

Read more about the settlement process here.

warning

While the callback feature is mandatory, we would like to emphasize that it is mainly a fail-safe feature. We strongly advice that it is not your primary mean of checking for payment updates.

When a change or update from the back-end system are made on a payment or transaction, Swedbank Pay will perform a callback to inform the payee (merchant) about this update.

Providing a callbackUrl in POST requests is mandatory. Below we provide three example scenarios of why this is important:

  1. If the payer closes the payment window, the merchant will never know what happened to the payment if callbackUrl is not implemented.
  2. If the payer stops up in a payment app such as Vipps or Swish, the payer will never come back to the merchant. This means that the merchant won’t know what happened to the payment unless callbackUrl is implemented.
  3. If a payer experiences a network error or something else happens that prevents the payer from being redirected from Swedbank Pay back to the merchant website, the callbackUrl is what ensures that you receive the information about what happened with the payment.
  • When a change or update from the back-end system are made on a payment or transaction, Swedbank Pay will perform an asynchronous server-to-server callback to inform the payee (merchant) about this update.
  • It is important to know that the callback is asynchronous, and not real-time. As we can’t guarantee when you get the callback, there could be a delay between when the payer is returned back to the merchant and when the callback arrives. If the merchant chooses to wait for the callback, the payer might be left at the merchant’s page until the response comes.
  • Swedbank Pay will make an HTTP POST to the callbackUrl that was specified when the payee (merchant) created the payment.
  • When the callbackUrl receives such a callback, an HTTP GET request must be made on the payment or on the transaction. The retrieved payment or transaction resource will give you the necessary information about the recent change/update.
  • As it isn’t scaled to be a primary source of updates, no given response time can be guaranteed, and a callback might fail. It will be retried if that should happen. Below are the retry timings, in seconds from the initial transaction time:
    • 30 seconds
    • 60 seconds
    • 360 seconds
    • 432 seconds
    • 864 seconds
    • 1265 seconds
  • A callback should return a 200 OK response.

The callback is sent from 91.132.170.1 in both the test and production environment.

To understand the nature of the callback, the type of transaction, its status, etc., you need to perform a GET request on the received URI and inspect the response. The transaction type or any other information can not and should not be inferred from the URI. See URI usage for more information.

Payment Instrument Callback

1
2
3
4
5
6
7
8
9
10
{
    "payment": {
        "id": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1",
        "number": 222222222
    },
    "transaction": {
        "id": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/authorizations/ec2a9b09-601a-42ae-8e33-a5737e1cf177",
        "number": 333333333
    }
}

When performing an HTTP GET request towards the URI found in the transaction.id field of the callback, the response is going to look something like the abbreviated example provided below.

The created authorization resource contains information about the authorization transaction made against a `` payment.

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
HTTP/1.1 200 OK
Content-Type: application/json

{
    "payment": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1",
    "authorization": {
        "id": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/authorizations/ec2a9b09-601a-42ae-8e33-a5737e1cf177",
        "itemDescriptions": {
            "id": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/transactions/ec2a9b09-601a-42ae-8e33-a5737e1cf177/itemDescriptions"
        },
        "transaction": {
            "id": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/transactions/ec2a9b09-601a-42ae-8e33-a5737e1cf177",
            "created": "2016-09-14T01:01:01.01Z",
            "updated": "2016-09-14T01:01:01.03Z",
            "type": "Authorization",
            "state": "Completed",
            "number": 1234567890,
            "amount": 1000,
            "vatAmount": 250,
            "description": "Test transaction",
            "payeeReference": "AH123456", 
            "isOperational": false,
            "problem": {
                "type": "https://api.payex.com/psp/errordetail//3DSECUREERROR",
                "title": "Error when complete authorization",
                "status": 400,
                "detail": "Unable to complete 3DSecure verification!",
                "problems": [
                ] 
            "operations": [
                {
                    "href": "/psp//payments/7e6cdfc3-1276-44e9-9992-7cf4419750e1/transactions/ec2a9b09-601a-42ae-8e33-a5737e1cf177",
                    "rel": "edit-authorization",
                    "method": "PATCH"
                }
            ]
        }
    }
}

Field Type Description  
payment string The relative URI and unique identifier of the payment resource this authorization belongs to. Please read about URI Usage to understand how this and other URIs should be used in your solution.  
authorization string The current authorization transaction resource.  
└➔ id string The relative URI and unique identifier of the authorization resource this authorization belongs to. Please read about URI Usage to understand how this and other URIs should be used in your solution.  
└➔ itemDescriptions object The object representation of the itemDescriptions resource.  
└─➔ id string The relative URI and unique identifier of the itemDescriptions resource this authorization belongs to. Please read about URI Usage to understand how this and other URIs should be used in your solution.  
└➔ transaction object The object representation of the generic transaction resource.  
└─➔ id string The relative URI and unique identifier of the transaction resource this authorization belongs to. Please read about URI Usage to understand how this and other URIs should be used in your solution.  
└─➔ created string The ISO-8601 date and time of when the transaction was created.  
└─➔ updated string The ISO-8601 date and time of when the transaction was updated.  
└─➔ type string Indicates the transaction type.  
└─➔ state string Indicates the state of the transaction, usually initialized, completed orfailed. If a partial authorization has been done and further transactionsare possible, the state will be awaitingActivity.  
└─➔ number string The transaction number, useful when there’s need to reference the transaction in human communication. Not usable for programmatic identification of the transaction, where id should be used instead.  
└─➔ amount integer The transaction amount (including VAT, if any) entered in the lowest monetary unit of the selected currency. E.g.: 10000 = 100.00 SEK, 5000 = 50.00 SEK.  
└─➔ vatAmount integer The payment’s VAT (Value Added Tax) amount, entered in the lowest monetary unit of the selected currency. E.g.: 10000 = 100.00 SEK, 5000 = 50.00 SEK. The vatAmount entered will not affect the amount shown on the payment page, which only shows the total amount. This field is used to specify how much of the total amount the VAT will be. Set to 0 (zero) if there is no VAT amount charged.  
└─➔ description string A 40 character length textual description of the purchase.  
└─➔ payeeReference string A unique reference from the merchant system. It is set per operation to ensure an exactly-once delivery of a transactional operation. See payeeReference for details. In Invoice Payments payeeReference is used as an invoice/receipt number, if the receiptReference is not defined.  
└─➔ receiptReference string A unique reference for the transaction. This reference is used as an invoice/receipt number.  
└─➔ failedReason string The human readable explanation of why the payment failed.  
└─➔ isOperational bool true if the transaction is operational; otherwise false.  
└─➔ operations array The array of operations that are possible to perform on the transaction in its current state.  

The sequence diagram below shows the HTTP POST you will receive from Swedbank Pay, and the two GET requests that you make to get the updated status.

sequenceDiagram
    Participant Merchant
    Participant SwedbankPay as Swedbank Pay

    activate SwedbankPay
    SwedbankPay->>+Merchant: POST <callbackUrl>
    deactivate SwedbankPay
    note left of Merchant: Callback by Swedbank Pay
    Merchant-->>+SwedbankPay: HTTP response
    Merchant->>+SwedbankPay: GET  payment
    deactivate Merchant
    note left of Merchant: First API request
    SwedbankPay-->>+Merchant: payment resource
    deactivate SwedbankPay

Problems

When performing operations against a resource in the Swedbank Pay API Platform, it will respond with a problem message that contain details of the error type if the request could not be successfully performed. Regardless of why the error occurred, the problem message will follow the same structure as specified in the Problem Details for HTTP APIs (RFC 7807) specification.

We generally use the problem message type and status code to identify the nature of the problem. The problems array contains objects with name and description that will often help narrow down the specifics of the problem, usually to the field in the request that was missing or contained invalid data.

The structure of a problem message will look like this:

Problem Example

1
2
3
4
5
6
7
8
9
10
11
12
{
    "type": "https://api.payex.com/psp/errordetail/<resource>/inputerror",
    "title": "There was an input error",
    "detail": "Please correct the errors and retry the request",
    "instance": "ec2a9b09-601a-42ae-8e33-a5737e1cf177",
    "status": 400,
    "action": "RetryNewData",
    "problems": [{
        "name": "CreditCardParameters.Issuer",
        "description": "minimum one issuer must be enabled"
    }]
}
Field Type Description
type string The URI that identifies the error type. This is the only field usable for programmatic identification of the type of error! When dereferenced, it might lead you to a human readable description of the error and how it can be recovered from.
title string The title contains a human readable description of the error.
detail string A detailed, human readable description of the error and how you can recover from it.
instance string The identifier of the error instance. This might be of use to Swedbank Pay support personnel in order to find the exact error and the context it occurred in.
status integer The HTTP status code that the problem was served with.
action string The action indicates how the error can be recovered from.
problems array The array of problem detail objects.
└➔ name string The name of the field, header, object, entity or likewise that was erroneous.
└➔ description string The human readable description of what was wrong with the field, header, object, entity or likewise identified by name.

Common Problems

All common problem types will have a URI in the format https://api.payex.com/psp/errordetail/<error-type>. The URI is an identifier that you can hard-code and implement logic around. It is currently not not possible to dereference this URI, although that might be possible in the future.

Type Status Description
inputerror 400 The server cannot or will not process the request due to an apparent client error (e.g. malformed request syntax, size to large, invalid request).
forbidden 403 The request was valid, but the server is refusing the action. The necessary permissions to access the resource might be lacking.
notfound 404 The requested resource could not be found, but may be available in the future. Subsequent requests are permissible.
systemerror 500 A generic error message.
configurationerror 500 A error relating to configuration issues.

Card Problems

There are a few problems specific to the creditcard resource that you may want to guard against in your integrations. All credit card problem types will have the following URI structure:

https://api.payex.com/psp/errordetail/creditcard/<error-type>

Contractual Problem Types

Type Status Description
cardbranddisabled 403 The card brand is disabled.
accountholdertyperejected 403 The account holder type is rejected.
cardtyperejected 403 The card type is rejected.
3dsecurerequired 403 The transaction was rejected by 3-D Secure.
authenticationstatusrejected 403 The authentication status was rejected.
frauddetected 403 The transaction was fraudulent.
3dsecuredeclined 403 3-D Secure declined the transaction.
velocitycheck 429 Indicates that the limit for how many times a card or different cards can be used for attempting a purchase has been reached.

Acquirer and 3-D Secure Problem Types

Type Status Description
3dsecureerror 400 3D Secure not working, try again some time later
cardblacklisted 400 Card blacklisted, the payer needs to contact their Card-issuing bank
paymenttokenerror 403 There was an error with the payment token.
carddeclined 403 The card was declined.
acquirererror 403 The acquirer responded with a generic error.
acquirercardblacklisted 403 Card blacklisted, the payer needs to contact their Card-issuing bank
acquirercardexpired 403 Wrong expire date or Card has expired and payer needs to contact their Card-issuing bank
acquirercardstolen 403 Card blacklisted, the payer needs to contact their Card-issuing bank
acquirerinsufficientfunds 403 Card does not have sufficient funds, the payer needs to contact their Card-issuing bank.
acquirerinvalidamount 403 Amount not valid by aquirer, contact support.ecom@payex.com
acquirerpossiblefraud 403 Transaction declined due to possible fraud, the payer needs to contact their Card-issuing bank.
3dsecureusercanceled 403 Transaction was Cancelled during 3DSecure verification
3dsecuredeclined 403 Transaction was declined during 3DSecure verification
frauddetected 403 Fraud detected, the payer needs to contact their Card-issuing bank.
badrequest 500 Bad request, try again after some time
internalservererror 500 Server error, try again after some time
3dsecureacquirergatewayerror 502 Problems reaching 3DSecure verification, try again after some time.
badgateway 502 Problems reaching the gateway, try again after some time
acquirergatewayerror 502 Problems reaching acquirers gateway, try again after some time
acquirergatewaytimeout 504 Problems reaching acquirers gateway, try again after some time