Skip to content

Instantly share code, notes, and snippets.

@asbjornu
Created June 12, 2020 12:19
Show Gist options
  • Save asbjornu/271859dad5f9e95d3400216743035f5f to your computer and use it in GitHub Desktop.
Save asbjornu/271859dad5f9e95d3400216743035f5f to your computer and use it in GitHub Desktop.
Problematic Liquid-Markdown file that causes mrmlnc.vscode-remark to crash

Payment Orders

In order to initialize the Payment Menu, you need to create a Payment Order. The paymentorders resource and how you interact with it is described below.

{% include payment-order-get.md show_status_operations=true %}

Creating a payment order

To create a payment order, you perform a POST request towards the paymentorders resource:

{% include payment-order-purchase.md %}

{% include description.md %}

Response

The response given when creating a payment order is equivalent to a GET request towards the paymentorders resource, as displayed above.

URLs

When creating a Payment Order, the urls field of the paymentOrder contains the related URIs, including where the consumer gets redirected when going forward with or cancelling a payment session, as well as the callback URI that is used to inform the payee (merchant) of changes or updates made to underlying payments or transaction.

{:.table .table-striped}

Required Field Type Description
{% icon check %} ︎︎︎︎︎ hostUrls array The array of URIs valid for embedding of Swedbank Pay Hosted Views.
{% icon check %} completeUrl string The URL that Swedbank Pay will redirect back to when the payer has completed his or her interactions with the payment. This does not indicate a successful payment, only that it has reached a final (complete) state. A GET request needs to be performed on the payment order to inspect it further.
{% icon check %} termsOfServiceUrl string {% include field-description-termsofserviceurl.md %}
cancelUrl string The URI to redirect the payer to if the payment is canceled, either by the payer or by the merchant trough an abort request of the payment or paymentorder.
paymentUrl string The URI that Swedbank Pay will redirect back to when the payment menu needs to be loaded, to inspect and act on the current status of the payment.
callbackUrl string The URI to the API endpoint receiving POST requests on transaction activity related to the payment order.
logoUrl string The URI to the logo that will be displayed on redirect pages. HTTPS is a requirement.

Payment Url

{% include payment-url.md api_resource="paymentorders" documentation_section="payment-menu" when="selecting the payment instrument Vipps or in the 3-D Secure verification for Credit Card Payments" full_reference=true %}

URLs Resource

It is possible to perform a GET request on the urls resource to retrieve its contents.

{:.code-header} Request

GET /psp/paymentorders/{{ page.payment_order_id }}/urls/ HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{:.code-header} Response

HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorder": "/psp/payments/{{ page.payment_order_id }}",
    "urls": {
        "id": "/psp/payments/{{ page.payment_order_id }}/urls",
        "hostUrls": [ "https://example.com", "https://example.net" ],
        "completeUrl": "https://example.com/payment-complete",
        "cancelUrl": "https://example.com/payment-canceled",
        "paymentUrl": "https://example.com/perform-payment",
        "callbackUrl": "http://api.example.com/payment-callback",
        "logoUrl": "http://merchant.com/path/to/logo.png",
        "termsOfServiceUrl": "http://merchant.com/path/to/tems"
    }
}

{:.table .table-striped}

Field Type Description
paymentorder string {% include field-description-id.md sub_resource="urls" %}
urls object The URLs object.
└➔ id string {% include field-description-id.md resource="urls" %}
└➔ hostsUrl string An array of the whitelisted URIs that are allowed as parents to a Hosted View, typically the URI of the web shop or similar that will embed a Hosted View within it.
└➔ completeUrl string The URL that Swedbank Pay will redirect back to when the payer has completed his or her interactions with the payment. This does not indicate a successful payment, only that it has reached a final (complete) state. A GET request needs to be performed on the payment order to inspect it further.
└➔ cancelUrl string The URI to redirect the payer to if the payment is canceled, either by the payer or by the merchant trough an abort request of the payment or paymentorder.
└➔ paymentUrl string The URI that Swedbank Pay will redirect back to when the payment menu needs to be loaded, to inspect and act on the current status of the payment.
└➔ callbackUrl string The URI that Swedbank Pay will perform an HTTP POST against every time a transaction is created on the payment. See callback for details.
└➔ logoUrl string The URI that will be used for showing the customer logo. Must be a picture with at most 50px height and 400px width.
└➔ termsOfServiceUrl string {% include field-description-termsofserviceurl.md %}

Order Items

The orderItems field of the paymentOrder is an array containing the items being purchased with the order. Used to print on invoices if the payer chooses to pay with invoice, among other things. orderItems is required in all requests. It should be specified on both payment order creation as well as on Capture.

{:.table .table-striped}

Required Field Type Description
{% icon check %} reference string A reference that identifies the order item.
{% icon check %} name string The name of the order item.
{% icon check %} type enum PRODUCT, SERVICE, SHIPPING_FEE, DISCOUNT, VALUE_CODE, or OTHER. The type of the order item.
{% icon check %} class string The classification of the order item. Can be used for assigning the order item to a specific product category, such as MobilePhone. Note that class cannot contain spaces and must follow the regex pattern [\w]* (a-zA-Z0-9_). Swedbank Pay may use this field for statistics.
itemUrl string The URL to a page that can display the purchased item, such as a product page
imageUrl string The URL to an image of the order item.
description string The human readable description of the order item.
discountDescription string The human readable description of the possible discount.
{% icon check %} quantity decimal The 4 decimal precision quantity of order items being purchased.
{% icon check %} quantityUnit string The unit of the quantity, such as pcs, grams, or similar.
{% icon check %} unitPrice integer The price per unit of order item, including VAT.
discountPrice integer If the order item is purchased at a discounted price. This field should contain that price, including VAT.
{% icon check %} vatPercent integer The percent value of the VAT multiplied by 100, so 25% becomes 2500.
{% icon check %} amount integer {% include field-description-amount.md %}
{% icon check %} vatAmount integer {% include field-description-vatamount.md %}

Items

The items field of the paymentOrder is an array containing items that will affect how the payment is performed.

{:.table .table-striped}

Required Field Type Description
creditCard object The credit card object.
└➔ rejectDebitCards bool true if debit cards should be declined; otherwise false per default. Default value is set by Swedbank Pay and can be changed at your request.
└➔ rejectDebitCards bool true if debit cards should be declined; otherwise false per default. Default value is set by Swedbank Pay and can be changed at your request.
└➔ rejectCreditCards bool true if credit cards should be declined; otherwise false per default. Default value is set by Swedbank Pay and can be changed at your request.
└➔ rejectConsumerCards bool true if consumer cards should be declined; otherwise false per default. Default value is set by Swedbank Pay and can be changed at your request.
└➔ rejectCorporateCards bool true if corporate cards should be declined; otherwise false per default. Default value is set by Swedbank Pay and can be changed at your request.
invoice object The invoice object.
└➔ feeAmount integer The fee amount in the lowest monetary unit to apply if the consumer chooses to pay with invoice.
swish object The swish object.
└➔ enableEcomOnly bool true to only enable Swish on ecommerce transactions.

The paymentOrders resource utilize several sub-resources, relating to underlying payments, the current payment active, payers and urls. Common sub-resources like payeeinfo, that are structurally identical for both payments and payments orders, are described in the Payment Resources section.

Operations

When a payment order resource is created and during its lifetime, it will have a set of operations that can be performed on it. The state of the payment order resource, what the access token is authorized to do, the chosen payment instrument and its transactional states, etc. determine the available operations before the initial purchase. A list of possible operations and their explanation is given below.

{:.code-header} Operations

{
    "paymentOrder": {
        "id": "/psp/paymentorders/{{ page.payment_order_id }}",
    }
    "operations": [
        {
            "method": "PATCH",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}",
            "rel": "update-paymentorder-abort",
            "contentType": "application/json"
        },
        {
            "method": "PATCH",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}",
            "rel": "update-paymentorder-updateorder",
            "contentType": "application/json"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/{{ page.payment_token }}",
            "rel": "redirect-paymentorder",
            "contentType": "text/html"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/core/scripts/client/px.paymentmenu.client.js?token={{ page.payment_token }}&culture=nb-NO",
            "rel": "view-paymentorder",
            "contentType": "application/javascript"
        },
        {
            "method": "POST",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}/captures",
            "rel": "create-paymentorder-capture",
            "contentType": "application/json"
        },
        {
            "method": "POST",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}/cancellations",
            "rel": "create-paymentorder-cancel",
            "contentType": "application/json"
        },
        {
            "method": "POST",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}/reversals",
            "rel": "create-paymentorder-reversal",
            "contentType": "application/json"
        },
        {
            "method": "GET",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}/paid",
            "rel": "paid-paymentorder",
            "contentType": "application/json"
        },
        {
            "method": "GET",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}/failed",
            "rel": "failed-paymentorder",
            "contentType": "application/problem+json"
        }
    ]
}

{:.table .table-striped}

Field Type Description
href string The target URI to perform the operation against.
rel string The name of the relation the operation has to the current resource.
method string GET, PATCH, POST, etc. The HTTP method to use when performing the operation.
contentType string The HTTP content type of the resource referenced in the href field.

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. The only thing that should be hard coded in the client is the value of the rel and the request that will be sent in the HTTP body of the request for the given operation.

{:.table .table-striped}

Operation Description
update-paymentorder-abort Aborts the payment order before any financial transactions are performed.
update-paymentorder-updateorder Updates the order with a change in the amount and/or vatAmount.
redirect-paymentorder Contains the URI that is used to redirect the consumer to the Swedbank Pay Payments containing the Payment Menu.
view-paymentorder Contains the JavaScript href that is used to embed the Payment Menu UI directly on the webshop/merchant site.
create-paymentorder-capture The second part of a two-phase transaction where the authorized amount is sent from the payer to the payee. It is possible to do a part-capture on a subset of the authorized amount. Several captures on the same payment are possible, up to the total authorization amount.
create-paymentorder-cancel Used to cancel authorized and not yet captured transactions. If a cancellation is performed after doing a part-capture, it will only affect the not yet captured authorization amount.
create-paymentorder-reversal Used to reverse a payment. It is only possible to reverse a payment that has been captured and not yet reversed.
paid-paymentorder Returns the information about a paymentorder that has the status paid.
failed-paymentorder Returns the information about a paymentorder that has the status failed.

{% include complete-url.md %}

View Payment Order

The view-paymentorder operation contains the URI of the JavaScript that needs to be set as a script element's src attribute, either client-side through JavaScript or server-side in HTML as shown below.

<!DOCTYPE html>
<html>
    <head>
        <title>Swedbank Pay Checkout is Awesome!</title>
    </head>
    <body>
        <div id="checkout"></div>
        <script src="{{ page.front_end_url }}/paymentmenu/core/scripts/client/px.paymentmenu.client.js?token={{ page.payment_token }}&culture=nb-NO"></script>
        <script language="javascript">
            payex.hostedView.paymentMenu({
                container: 'checkout',
                culture: 'nb-NO',
                onPaymentCompleted: function(paymentCompletedEvent) {
                    console.log(paymentCompletedEvent);
                },
                onPaymentFailed: function(paymentFailedEvent) {
                    console.log(paymentFailedEvent);
                },
                onPaymentCreated: function(paymentCreatedEvent) {
                    console.log(paymentCreatedEvent);
                },
                onPaymentToS: function(paymentToSEvent) {
                    console.log(paymentToSEvent);
                },
                onPaymentMenuInstrumentSelected: function(paymentMenuInstrumentSelectedEvent) {
                    console.log(paymentMenuInstrumentSelectedEvent);
                },
                onError: function(error) {
                    console.error(error);
                },
            }).open();
        </script>
    </body>
</html>

Update Order

Change amount and vat amount on a payment order. If you implement UpdateOrder you need to refresh() the Payment Menu front end so the new amount is shown to the end customer.

{:.code-header} Request

PATCH /psp/paymentorders/{{ page.payment_order_id }} HTTP/1.1
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "paymentorder": {
        "operation": "UpdateOrder",
        "amount": 1500,
        "vatAmount": 375,
        "orderItems": [
            {
                "reference": "P1",
                "name": "Product1",
                "type": "PRODUCT",
                "class": "ProductGroup1",
                "itemUrl": "https://example.com/shop/products/1234",
                "imageUrl": "https://example.com/products/product1.jpg",
                "description": "Product description",
                "discountDescription": "Volume discount",
                "quantity": 351.3514,
                "quantityUnit": "pcs",
                "unitPrice": 300,
                "discountPrice": 200,
                "vatPercent": 2500,
                "amount": 1000,
                "vatAmount": 250
            },
            {
                "reference": "P2",
                "name": "Product2",
                "type": "PRODUCT",
                "class": "ProductGroup1",
                "description": "Product description",
                "quantity": 9876.1531,
                "quantityUnit": "pcs",
                "unitPrice": 500,
                "vatPercent": 2500,
                "amount": 500,
                "vatAmount": 125
            }
        ]
    }
}

{:.code-header} Response

HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorder": {
        "id": "/psp/paymentorders/{{ page.payment_order_id }}",
        "created": "2018-09-14T13:21:29.3182115Z",
        "updated": "2018-09-14T13:21:57.6627579Z",
        "operation": "Purchase",
        "state": "Ready",
        "currency": "SEK",
        "amount": 1500,
        "vatAmount": 0,
        "remainingCaptureAmount": 1500,
        "remainingCancellationAmount": 1500,
        "remainingReversalAmount": 0,
        "description": "Test Purchase",
        "initiatingSystemUserAgent": "PostmanRuntime/3.0.1",
        "userAgent": "Mozilla/5.0...",
        "language": "nb-NO",
        "urls" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/urls" },
        "payeeInfo" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payeeinfo" },
        "settings": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/settings" },
        "payers": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payers" },
        "orderItems" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/orderItems" },
        "metadata": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/metadata" },
        "payments": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payments" },
        "currentPayment": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/currentpayment" }
    },
    "operations": [
        {
            "method": "PATCH",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}",
            "rel": "update-paymentorder-abort",
            "contentType": "application/json"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/{{ page.payment_token }}",
            "rel": "redirect-paymentorder",
            "contentType": "text/html"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/core/scripts/client/px.paymentmenu.client.js?token={{ page.payment_token }}&culture=nb-NO",
            "rel": "view-paymentorder",
            "contentType": "application/javascript"
        }
    ]
}

The response given when changing a payment order is equivalent to a GET request towards the paymentorders resource, as displayed above.

{% include alert.html type="informative" icon="info" body=" After updating the Payment Order, remember to call .refresh() on the Payment Menu in JavaScript." %}

Abort

To abort a payment order, perform the update-paymentorder-abort operation that is returned in the payment order response. You need to include the following in the request body:

{:.code-header} Request

PATCH /psp/paymentorders/{{ page.payment_order_id }} HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
  "paymentorder": {
    "operation": "Abort",
    "abortReason": "CancelledByConsumer"
  }
}

{:.code-header} Response

HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorder": {
        "id": "/psp/paymentorders/{{ page.payment_order_id }}",
        "created": "2018-09-14T13:21:29.3182115Z",
        "updated": "2018-09-14T13:21:57.6627579Z",
        "operation": "Purchase",
        "state": "Ready",
        "currency": "SEK",
        "amount": 1500,
        "vatAmount": 0,
        "remainingCaptureAmount": 1500,
        "remainingCancellationAmount": 1500,
        "remainingReversalAmount": 0,
        "description": "Test Purchase",
        "initiatingSystemUserAgent": "PostmanRuntime/3.0.1",
        "userAgent": "Mozilla/5.0...",
        "language": "nb-NO",
        "urls" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/urls" },
        "payeeInfo" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payeeinfo" },
        "settings": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/settings" },
        "payers": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payers" },
        "orderItems" : { "id": "/psp/paymentorders/{{ page.payment_order_id }}/orderItems" },
        "metadata": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/metadata" },
        "payments": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/payments" },
        "currentPayment": { "id": "/psp/paymentorders/{{ page.payment_order_id }}/currentpayment" }
    },
    "operations": [
        {
            "method": "PATCH",
            "href": "{{ page.api_url }}/psp/paymentorders/{{ page.payment_order_id }}",
            "rel": "update-paymentorder-abort",
            "contentType": "application/json"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/{{ page.payment_token }}",
            "rel": "redirect-paymentorder",
            "contentType": "text/html"
        },
        {
            "method": "GET",
            "href": "{{ page.front_end_url }}/paymentmenu/core/scripts/client/px.paymentmenu.client.js?token={{ page.payment_token }}&culture=nb-NO",
            "rel": "view-paymentorder",
            "contentType": "application/javascript"
        }
    ]
}

The response given when aborting a payment order is equivalent to a GET request towards the paymentorders resource, as displayed above. with its state set to Aborted.

Cancel

{% include payment-order-cancel.md %}

Reversal

{% include payment-order-reversal.md %}

Transactions

{% include transactions.md api_resource="paymentorders" documentation_section="checkout" %}

Transaction

{% include transaction.md api_resource="paymentorders" documentation_section="checkout" %}

Recurring Payments

If you want to enable subsequent recurring – server-to-server – payments, you need to create a recurrence token. This token will be utilized after the initial payment order. Recurring payments must be activated on the contract with Swedbank Pay in order to work.

Recurrence Token

  • When initiating a Purchase payment order, you need to make sure that the field generateRecurrenceToken is set to true. This recurrence token will stored in the authorization transaction sub-resource on the underlying payment resource.
  • When initiating a Verify payment order, a recurrence token will be generated automatically. This recurrence token is stored in the verification sub-resource on the underlying payment resource.

You can view the current payment resource, containg the recurrence token and other payment instrument properties, by expanding the sub-resource currentpayment when doing a GET request on the paymentorders resource.

{:.code-header} Request

GET /psp/paymentorders/{{ page.payment_order_id }}?$expand=currentpayment HTTP/1.1
Host: {{ page.api_host }}

Creating Recurring Payments

When you have a recurrenceToken token safely tucked away, you can use this token in a subsequent Recur payment order. This will be a server-to-server affair, as we have tied all necessary payment instrument details related to the recurrence token during the initial payment order.

{:.code-header} Request

POST /psp/paymentorders HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
  "paymentorder": {
    "operation": "Recur",
    "recurrenceToken": "{{ page.payment_order_id }}",
    "currency": "SEK",
    "amount": 1000,
    "vatAmount": 250,
    "description": "Test Purchase",
    "userAgent": "Mozilla/5.0...",
    "language": "sv-SE",
    "urls": {
      "callbackUrl": "https://example.com/callback"
    },
    "payeeInfo": {
      "payeeId": "{{ page.merchant_id }}"
      "payeeReference": "CD1234",
      "payeeName": "Merchant1",
      "productCategory": "A123",
      "orderReference": "or-12456",
      "subsite": "Subsite1"
    },
    "orderItems": [
      {
        "reference": "P1",
        "name": "Product1",
        "type": "PRODUCT",
        "class": "ProductGroup1",
        "itemUrl": "https://example.com/shop/id=123",
        "imageUrl": "https://example.com/product1.jpg",
        "description": "Product 1 description",
        "discountDescription": "Volume discount",
        "quantity": 4,
        "quantityUnit": "pcs",
        "unitPrice": 300,
        "discountPrice": 200,
        "vatPercent": 2500,
        "amount": 1000,
        "vatAmount": 250
      }
    ],
    "metadata": {
      "key1": "value1",
      "key2": 2,
      "key3": 3.1,
      "key4": false
    }
  }
}

Purchase Flow

sequenceDiagram
    participant Payer
    participant ConsumerSubscription
    participant Merchant
    participant SwedbankPay as Swedbank Pay

    rect rgba(81,43,43,0.1)
        note left of Payer: Checkin
        activate Payer
        Payer ->>+ SwedbankPay: Checkin procedure
        deactivate Payer
    end
    rect rgba(55, 91, 134,0.1)
        activate Payer
        note left of Payer: Payment Menu
        Payer ->>+ Merchant: Initiate Purchase
        deactivate Payer
        Merchant ->>+ SwedbankPay: POST/psp/paymentorders (generateRecurrenceToken = True)
        deactivate Merchant
        SwedbankPay -->>+ Merchant: rel:view-paymentorder
        deactivate SwedbankPay
        Merchant -->>- Payer: Display Payment Menu on Merchant Page
        activate Payer
        Payer ->> Payer: Initiate Payment Menu Hosted View (open iframe)
        Payer -->>+ SwedbankPay: Show Payment UI page in iframe
        deactivate Payer
        SwedbankPay ->>+ Payer: Do payment logic
        deactivate SwedbankPay
        SwedbankPay -->>+ Merchant: POST Payment Callback
        SwedbankPay -->>- Payer: Payment Status
        Payer -->>+ Merchant: Redirect to Payment Complete URL
        Merchant ->>+ SwedbankPay: GET/psp/paymentorders/<paymentOrderId>
        SwedbankPay -->>+ Merchant: Payment Order Status
    end
    rect rgba(63, 204, 164,0.1)
        note left of Payer: Capture
        activate Merchant
        Merchant ->>+ SwedbankPay: POST/psp/paymentorders/<paymentOrderId>/captures
        deactivate Merchant
        SwedbankPay -->>- Merchant: Capture status
        note right of Merchant: Capture here only if the purchased<br/>goods don't require shipping.<br/>If shipping is required, perform capture<br/>after the goods have shipped.<br>Should only be used for <br>PaymentInstruments that support <br>Authorizations.
    end
    rect rgba(94, 108, 23,0.1)
        note left of Payer: Recurring payment
        activate ConsumerSubscription
        ConsumerSubscription ->>+ Merchant: Start recurring payment
        deactivate ConsumerSubscription
        note left of Merchant: Server-to-Server request at a later date
        activate Merchant
        Merchant ->>+ SwedbankPay: POST Card Payments (operation=RECUR) (reccurenceToken included)
        deactivate Merchant
        SwedbankPay -->>- Merchant: Payment resource

        opt [Intent=Authorization]
            Merchant ->>+ SwedbankPay: Create-capture
            SwedbankPay -->>- Merchant: Transaction resource
        end
        activate Merchant
        Merchant -->>- ConsumerSubscription: display purchase result
    end
Loading

Purchase Payments

The Purchase operation is used in all common purchase scenarios.

{:.code-header} Purchase

{
    "paymentorder": {
        "operation": "Purchase"
    {
}

Verify Payments

The Verify operation lets you post verifications to confirm the validity of credit card information, without reserving or charging any amount. This option is mainly used to initiate a recurring payment scenario where the card will be charged at a later date. The request body is equivalent to a Purchase order with credit card as the selected item. A recurrence token will be generated automatically, rendering the parameter generateRecurrenceToken unnecessary for this operation.

{:.code-header} Verify

{
    "paymentorder": {
        "operation": "Verify"
    {
}

Payments Resource

A payment order is able to hold more than one payment object, even though a successful payment order only harbour one successful payment. This is necessary as the consumer might select and initiate a payment option that is not followed through successfully. I.e. if the consumer cancels an invoice payment, a cancel transaction will still be tied to that particular invoice payment resource. This payment resource will continue to exist, even if the consumer successfully should finish the purchase with a credit card payment instead.

{:.code-header} Request

GET /psp/paymentorders/{{ page.payment_order_id }}/payments HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{
    "paymentorder": "/psp/paymentorders/{{ page.payment_order_id }}",
    "payments": {
        "id": "/psp/paymentorders/{{ page.payment_order_id }}/payments",
        "paymentList" : [
            {
                "id": "/psp/creditcard/payments/{{ page.transaction_id }}",
                "instrument" : "CreditCard",
                "created": "2016-09-14T13:21:29.3182115Z"
            },
            {
                "id": "/psp/invoice/payments/{{ page.payment_id }}",
                "instrument" : "Invoice",
                "created": "2016-09-14T13:21:29.3182115Z"
            }
        ]
    }
}

{:.table .table-striped}

Field Type Description
paymentorder object The payment order object.
payments object The payments object.
└➔ id string {% include field-description-id.md resource="payments" %}
└➔ paymentList array The array of payment objects.
└─➔ id string {% include field-description-id.md %}
└─➔ instrument string The name of the payment instrument.
└─➔ created string The ISO-8601 date and time of when the payment was created.

Current Payment Resource

The currentpayment resource displays the payment that are active within the payment order container.

{:.code-header} Request

GET /psp/paymentorders/{{ page.payment_order_id }}/currentpayment HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{:.code-header} Response

HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorder": "/psp/paymentorders/{{ page.payment_order_id }}",
    "menuElementName": "paymentorders",
    "payment": {
        "recurrenceToken": "{{ page.payment_order_id }}",
        "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}",
        "number": 1234567890,
        "instrument": "CreditCard",
        "created": "2016-09-14T13:21:29.3182115Z",
        "updated": "2016-09-14T13:21:57.6627579Z",
        "operation": "Purchase",
        "intent": "Authorization",
        "state": "Ready",
        "currency": "NOK",
        "amount": 1500,
        "remainingCaptureAmount": 1500,
        "remainingCancellationAmount": 1500,
        "remainingReversalAmount": 0,
        "description": "Test Purchase",
        "payerReference": "AB1234",
        "userAgent": "Mozilla/5.0...",
        "language": "nb-NO",
        "prices": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/prices" },
        "transactions": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/transactions" },
        "authorizations": { "id": "/psp/paymentorderspayments/{{ page.payment_order_id }}/authorizations" },
        "captures": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/captures" },
        "cancellations": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/cancellations" },
        "reversals": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/reversals" },
        "verifications": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/verifications" },
        "urls" : { "id": "/psp/paymentorderspayments/{{ page.payment_order_id }}/urls" },
        "payeeInfo" : { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/payeeInfo" },
        "metadata" : { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/metadata" },
        "settings": { "id": "/psp/paymentorders/payments/{{ page.payment_order_id }}/settings" }
    },
    "operations": []
}

{:.table .table-striped}

Field Type Description
paymentorder string {% include field-description-id.md resource="paymentorder" sub_resource="payment" %}
menuElementName string creditcard, invoice, etc. The name of the selected menu element.
payment object The payment object.
└➔ recurrenceToken string The created recurrenceToken, if operation: Verify or generateRecurrenceToken: true was used.
└➔ id string {% include field-description-id.md %}
└➔ number integer The payment number, useful when there's need to reference the payment in human communication. Not usable for programmatic identification of the payment, for that id should be used instead.
└➔ instrument string The payment instrument used.
└➔ created string The ISO-8601 date of when the payment was created.
└➔ updated string The ISO-8601 date of when the payment was updated.
└➔ operation string Purchase, payout, Verify or recur.The type of the initiated payment.
└➔ intent string The intent of the payment.
└➔ state string Ready, Pending, Failed or Aborted. Indicates the state of the payment. This field is only for status display purposes.
└➔ currency string The currency of the payment.
└➔ prices object The prices object.
└─➔ amount integer {% include field-description-amount.md %}
└─➔ remainingCaptureAmount integer The available amount to capture.
└─➔ remainingCancelAmount integer The available amount to cancel.
└─➔ remainingReversalAmount integer The available amount to reverse.
└➔ description string(40) {% include field-description-description.md documentation_section="checkout" %}
└➔ payerReference string The reference to the consumer from the merchant system, like mobile number, customer number etc.
└➔ userAgent string The user agent string of the consumer's browser.
└➔ language string {% include field-description-language.md api_resource="paymentorders" %}

{% include prices.md api_resource="paymentorders" %}

Payer Resource

The payer resource contains payer information related to the payment order. The information is retrieved via a consumer profile token (consumerProfileRef), from the Consumers resource during login/checkin.

{:.code-header} Request

GET /psp/paymentorders/{{ page.payment_order_id }}/payers/ HTTP/1.1
Host: {{ page.api_host }}
Authorization: Bearer <AccessToken>
Content-Type: application/json

{:.code-header} Response

HTTP/1.1 200 OK
Content-Type: application/json

{
    "paymentorder": "/psp/paymentorders/{{ page.payment_order_id }}",
    "payer" : {
        "id": "/psp/paymentorders/{{ page.payment_order_id }}/payer",
        "reference": "reference to payer",
        "email": "email",
        "msisdn": "msisdn",
        "shippingAddress": {
            "addressee": "firstName + lastName",
            "coAddress": "coAddress",
            "streetAddress": "streetAddress",
            "zipCode": "zipCode",
            "city": "city",
            "countryCode": "countryCode"
        }
    }
}

{:.table .table-striped}

Field Type Description
paymentorder string {% include field-description-id.md resource="paymentorder" sub_resource="payer" %}
payer object The payer object.
└➔ id string {% include field-description-id.md resource="payer" %}
└➔ email string Payer's registered email address.
└➔ msisdn string Payer's registered mobile phone number.
└➔ shippingAddress object The shipping address object related to the payer.
└─➔ addresse object The shipping address object related to the payer.
└─➔ coAddress string Payer' s c/o address, if applicable.
└─➔ streetAddress string Payer's street address
└─➔ zipCode string Payer's zip code
└─➔ city string Payer's city of residence
└─➔ countryCode string Country Code for country of residence.

Enable or Disable Payment Menu

It is possible to disable the payment menu when only one instrument exist by setting the disablePaymentMenu field to true. The default value is false, exemplified below.

{:.code-header} Request

{
    "paymentorder": {
        "disablePaymentMenu": false
    {
}

{:.text-center} example disablePaymentMenu = false{:width="450" :height="850"}

Setting disablePaymentMenu field to true removes all other payment instruments but the one that is available. This feature is only valuable to set to true if you have only one payment instrument available. By setting it to true will remove the frame around the menu and show only the instrument.

{:.code-header} Request

{
    "paymentorder": {
        "disablePaymentMenu": true
    {
}

{:.text-center} example disablePaymentMenu = true{:width="463" :height="553"}

Payment Menu Events

During operation in the Payment Menu, several events can occur. They are described below.

onPaymentMenuInstrumentSelected

This event triggers when a user actively changes payment instrument in the Payment Menu. The onPaymentMenuInstrumentSelected event is raised with the following event argument object:

{:.code-header} onPaymentMenuInstrumentSelected event object

{
    "name": "menu identifier",
    "instrument": "creditcard | vipps | swish | invoice",
}

{:.table .table-striped}

Field Type Description
name string The name and identifier of specific instrument instances - i.e. if you deploy more than one type of credit card payments, they would be distinguished by name.
instrument string Creditcard, vipps, swish, invoice. The instrument selected by the user.

onPaymentCreated

This event triggers when a user has selected a payment instrument and actively attempts to perform a payment. The onPaymentCreate event is raised with the following event argument object:

{:.code-header} onPaymentCreated event object

{
    "id": "/psp/paymentorders/payments/{{ page.payment_id }}",
    "instrument": "creditcard | vipps | swish | invoice",
}

{:.table .table-striped}

Field Type Description
id string {% include field-description-id.md %}
instrument string Creditcard, vipps, swish, invoice. The instrument selected when initiating the payment.

onPaymentCompleted

This event triggers when a payment has completed successfully. The onPaymentCompleted event is raised with the following event argument object:

{:.code-header} onPaymentCompleted event object

{
    "id": "/psp/paymentorders/payments/{{ page.payment_id }}",
    "redirectUrl": "https://en.wikipedia.org/wiki/Success"
}

{:.table .table-striped}

Field Type Description
id string {% include field-description-id.md %}
redirectUrl string The URI the user will be redirect to after a completed payment.

onPaymentCanceled

This event triggers when the user cancels the payment. The onPaymentCanceled event is raised with the following event argument object:

{:.code-header} onPaymentCanceled event object

{
    "id": "/psp/paymentorders/payments/{{ page.payment_id }}",
    "redirectUrl": "https://en.wikipedia.org/wiki/Canceled"
}

{:.table .table-striped}

Field Type Description
id string {% include field-description-id.md %}
redirectUrl string The URI the user will be redirect to after a canceled payment.

onPaymentTransactionFailed

This event triggers when a payment attempt fails, further attempts can be made for the payment. An error message will appear in the payment UI, and the consumer will be able to try again or choose another payment instrument. The onPaymentTransactionFailed event is raised with the following event argument object:

{:.code-header} onPaymentTransactionFailed event object

{
    "id": "/psp/paymentorders/payments/{{ page.payment_id }}",
    "details": "[HttpCode ProblemTitle]"
}

{:.table .table-striped}

Field Type Description
id string {% include field-description-id.md %}
details string A human readable and descriptive text of the error.

onPaymentFailed

This event triggers when a payment has failed, disabling further attempts to perform a payment. The onPaymentFailed event is raised with the following event argument object:

{:.code-header} onPaymentFailed event object

{
    "id": "/psp/paymentorders/payments/{{ page.payment_id }}",
    "redirectUrl": "https://en.wikipedia.org/wiki/Failed"
}

{:.table .table-striped}

Field Type Description
id string {% include field-description-id.md %}
redirectUrl string The URI the user will be redirect to after a failed payment.

onPaymentTermsOfService

This event triggers when the user clicks on the "Display terms and conditions" link. The onPaymentTermsOfService event is raised with the following event argument object:

{:.code-header} onPaymentTermsOfService event object

{
    "origin": "owner | merchant",
    "openUrl": "https://example.org/terms.html"
}

{:.table .table-striped}

Field Type Description
origin string owner, merchant. The value is always merchant unless Swedbank Pay hosts the view.
openUrl string The URI containing Terms of Service and conditions.

onError

This event triggers during terminal errors or if the configuration fails validation. The onError event will be raised with the following event argument object:

{:.code-header} onError event object

{
    "origin": "consumer | paymentmenu | creditcard | invoice | ...",
    "messageId": "<unique message ID>",
    "details": "Descriptive text of the error"
}

{:.table .table-striped}

Field Type Description
origin string consumer, paymentmenu, creditcard, identifies the system that originated the error.
messageId string A unique identifier for the message.
details string A human readable and descriptive text of the error.

Callback

  • Setting a callbackUrl in the HTTP POST API is optional, but highly recommended. If a payer closes the browser window, a network error or something else happens that prevents the payer from being redirect from Swedbank Pay back to the merchant website, the callback is what ensures that you receive 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.
  • 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.
  • The callback will be retried if it fails. Below are the retry timings, in seconds from the initial transaction time:
    • 30 seconds
    • 60 seconds
    • 360 seconds
    • 432 seconds
    • 864 seconds
    • 1265 seconds
  • The callback is sent from the following IP address 82.115.146.1.

{:.code-header} Payment Order Callback

{
    "orderReference": "OR-123456",
    "paymentOrder":{
        "id": "/psp/paymentorders/{{ page.payment_order_id }}",
        "instrument": "<payment instrument>"
    },
    "payment":{
        "id": "/psp/<payment instrument>/payments/{{ page.payment_id }}",
        "number": 222222222
    },
    "transaction":{
        "id": "/psp/<payment instrument>/payments/{{ page.payment_id }}/<transaction type>/{{ page.transaction_id }}",
        "number": 333333333
    }
}

{:.table .table-striped}

Parameter Description
orderReference The orderReference sent in on create paymentOrder
Payment Instrument CreditCard, Invoice, Swish, Vipps, DirectDebit, MobilePay
Transaction Type Authorization, Capture, Cancellation, Reversal

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 Merchant
        activate SwedbankPay
            SwedbankPay->Merchant: POST <callbackUrl>
            note left of Merchant: Callback by Swedbank Pay
            Merchant-->SwedbankPay: HTTP response
        deactivate SwedbankPay
    deactivate Merchant

    activate Merchant
        Merchant->SwedbankPay: GET <payment instrument> payment
        activate SwedbankPay
            note left of Merchant: First API request
            SwedbankPay-->Merchant: payment resource
        deactivate SwedbankPay
    deactivate Merchant
Loading

Problems

When performing operations against the API, 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] specification.

The structure of a problem message will look like this:

{
    "type": "https://api.payex.com/psp/errordetail/paymentorders/inputerror",
    "title": "There was an input error",
    "detail": "Please correct the errors and retry the request",
    "instance": "{{ page.transaction_id }}",
    "status": 400,
    "action": "RetryNewData",
    "problems": [{
        "name": "CreditCardParameters.Issuer",
        "description": "minimum one issuer must be enabled "
    }]
}

{:.table .table-striped}

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.
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 description of what was wrong with the field, header, object, entity or likewise identified by name.

{% include common-problem-types.md %}

{% include expand-parameter.md api_resource="paymentorders" %}

{% include payee-info.md api_resource="paymentorders" %}

{% include merchant-authenticated-consumer.md %}

{% include settlement-reconciliation.md api_resource="paymentorders" %}

Updating Payment Menu

When the contents of the shopping cart changes or anything else that affects the amount occurs, the paymentorder must be updated and the Payment Menu must be refreshed.

{% include alert.html type="informative" icon="info" body= "Features that are not described in the previous sections must not be used, although they are available in the API. Flags that can be turned to true must be kept false as described in this standard setup documentation." %}

{% include alert.html type="informative" icon="info" body= "Your integration must be resilient to change. Properties, operations, headers, etc., that aren't understood in any response must be ignored. Don't expect a specific order of elements. When in doubt, please follow the robustness principle." %}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment