This site requires javascript to be enabled.

American Express

Results for

Results for Searching

Integration

Description

This is a product specific integration guide that will go over all the available features and how to use them.

Features or customization options that are not strictly required for card payments may be skipped in this guide, pages with extra information will be hyperlinked where appropriate.

Prerequisites

To follow along with this guide, please ensure that you have the following ready:

MyCheckout hosted payment pages 

The fastest way to start accepting card payments is to make use of the MyCheckout hosted payment pages.

As we host the pages and handle the card data, you only need to be PCI SAQ-A compliant rather than any of the higher levels with more stringent requirements.

To start using the MyCheckout hosted payment pages, you only need to make a POST /v1/{merchantId}/hostedcheckouts API call with an order object containing a amountOfMoney object and a customer object. The customer object has a lot of options but only the billingAddress object with a countryCode property is required for a basic checkout.

Here's an example of a minimum hostedcheckouts payload:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    }
}

This will return a response like this:


{
   "RETURNMAC" : "33893c8a-1e6f-4e02-9015-9d4e34b08d41",
   "hostedCheckoutId" : "0634e88f-7255-71ff-860e-3f55f70978cc",
"merchantReference" : "EXAMPLE_2023-05-11_18:05:03",    "partialRedirectUrl" : "pay1.preprod.secured-by-ingenico.com/checkout/1010-e6e2e548a8024375a3c22ae4cea99f59:0634e88f-7255-71ff-860e-3f55f70978cc:80152ac992ea431ea1da027d1c3e6df4" }

From the response, the essential properties are hostedCheckoutId and partialRedirectUrl. The hostedCheckoutId can be used in subsequent API calls such as GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} which will allow you to retrieve details regarding the transaction.

The partialRedirectUrl is used to create a URL you can redirect your consumer to. By default, we configure every account with the subdomain payment so you can always concatenate https://payment. with the partialRedirectUrl, which will result in a full URL such as:

https://payment.pay1.preprod.secured-by-ingenico.com/checkout/1010-e6e2e548a8024375a3c22ae4cea99f59:0634e88f-7255-71ff-860e-3f55f70978cc:80152ac992ea431ea1da027d1c3e6df4

More detailed information on how to customize the MyCheckout hosted payment pages (e.g. subdomains, design, languages etc.) can be found here.

At its core, this is all you need to start accepting card payments, more complex options will be covered later.

If you want to retrieve data after more than 2 hours, then use the hostedCheckoutId while it's still valid to call the GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} API request and store the createdPaymentOutput.payment.Id value from the response. The paymentId can be used at any time in GET /v1/{merchantId}/payments/{paymentId} API call to request the latest payment status. 

We'll also send a Webhooks event containing the paymentId if you have this feature configured for your account.

Your own checkout page 

A second option for accepting card payments is using your own checkout pages with our Server API — it gives you access to all our functionality if you need more control over the payment process and customization options. We provide our SDKs in multiple programming languages to help you build your integration (or you can integrate our API from scratch).

Within this option, you can choose from the following variations depending on your PCI DSS compliance level and your requirements.

Client Encryption

The Client API can be used for a variety of purposes. A good example is that it allows you to collect card data from your consumers without needing to be PCI SAQ-D compliant, as an alternative to using MyCheckout.

All you need is to create a session via the POST /v1/{merchantId}/sessions API call. This will grant you access to the Client API.

It is highly recommended that you use our Client SDKs.

This guide only describes generally what steps you need to go through, the in-depth SDK pages describe how to perform the steps with SDK specific examples.

We provide these Client SDKs for:

These pages include detailed information on how to use the SDKs with language specific examples.

We also have reference implementations showing you how to use these SDKs on GitHub.

Even if you choose to not use our Client SDKs we highly recommend that you use the encryption methods we provide in these SDKs.

Here are some additional, not purely cards related, details you can expand to view.

Expand Client Encryption Section
Basic Usage

We will use card payments as the example as it also demonstrates the PCI compliance aspects.

When you utilize the Client API, you will not directly handle the data required for the various payment products; all data input by the consumer (e.g. card data )will be securely encrypted on the client side.

In the case of card payments, you need to be PCI SAQ-AEP compliant to use the Client API.

The general steps required to perform a card payment are as follows:

  1. Create a session via our Server API
  2. Use the session to perform a GET /client/v1/{customerId}/products or GET /client/v1/{customerId}/products/{paymentProductId} API call to retrieve all the product information for the products configured for your Merchant ID.
  3. Use the payment product information to determine which properties need to be collected from the consumers and display them.
  4. Use the session to perform a POST /client/v1/{customerId}/services/getIINdetails to ensure that the card number that the consumer input is supported by your Merchant ID.
  5. Use the session to retrieve the publicKey.
  6. Encrypt the data input by the consumer.
  7. Send the encrypted data to us to perform the payment.

The process for non-card products is similar but for example there would be no requirement to verify IIN details.

Session Creation
Basic Session

To create a session perform a POST /v1/{merchantId}/sessions API call. A body can be provided to customize the session but it is not required. The call will result in a response such as this:


{
    "assetUrl": "https://assets.pay1.preprod.secured-by-ingenico.com/",
    "clientApiUrl": "https://ams1.preprod.api-ingenico.com/client",
    "clientSessionId": "0ec162d940ab4effa56ff6ee7fe999f6",
    "customerId": "1010-73478d14199b45c4a3c72fe41e40d6bc",
    "region": "EU"
}

The assetUrl is used to retrieve assets such as logos of payment products, for example, GET /client/v1/{customerId}/products/{paymentProductId} will return various details for a specific Payment Product and one of those is the URI for the logo which can be combined with the assetUrl for the final URL.

The clientApiUrl and customerId are used to construct the API endpoint for all Client API calls.

The clientSessionId will be used to construct the Authorization header for Client API calls.

You are now ready to perform Client API calls and can retrieve the data required to show the correct data input fields to the consumer.

Session Customization

As mentioned earlier, you can customize the session if required. There are 2 options:

  • Product Filtering
  • Tokens

The product filtering option, enabled through the paymentProductFilters property, allows you to limit which payment products are valid for this session, and this can be done either through whitelisting or blacklisting.

This object can contain either the exclude or restrictTo properties, with the former being the blacklist option and the latter the whitelist option.

Both of these objects can contain either a groups array or a products array. There is currently only 1 valid value for the groups array which is cards (this includes every payment product labeled as payment method Cards (debit & credit) here). This allows you to either whitelist or blacklist a set of payment products at once without having to separately list all the payment product IDs. The products array will simply contain a list of payment product IDs.

You can use it like this:


        "paymentProductFilters": {
            "restrictTo": {
                "products": [
                    1,
                    3
                ]
            }
        }

In the above example, only Visa and Mastercard would be valid for the session regardless of which other payment products are configured for the Merchant ID.

The tokens option, enabled through the tokens property, allows you to provide an array of previously stored tokens which will be eligible for the consumer to use. For example, if a consumer previously indicated that they wished to store their card data for future use and you created a token out of it, this is an example of how you would present it as a valid option to use for payments to the consumer:


    "tokens": [
        "b3b7c625-8561-47c0-9375-1fe9cd8f33f9",
        "e2ae0b6b-20d3-4193-9594-a1d6f5cb92d1",
        "7fdb13e4-b0c2-4550-8c64-906a5d96c5eb"
    ]
Product Fields

In order to know what information needs to be collected from the consumer for any given payment product, you need to perform a GET /client/v1/{customerId}/products or GET /client/v1/{customerId}/products/{paymentProductId} API call, where the former gives you the details for every payment product configured for your account, and the latter for a specified payment product.

For example, if you were to request all details for Visa, you would get a response similar to this:

Expand example response

{
    "deviceFingerprintEnabled": true,
    "allowsInstallments": false,
    "allowsRecurring": true,
    "allowsTokenization": true,
    "authenticationIndicator": {
        "name": "AUTHENTICATIONINDICATOR",
        "value": "0"
    },
    "autoTokenized": false,
    "displayHints": {
        "displayOrder": 6,
        "label": "Visa",
        "logo": "templates/master/global/css/img/ppimages/pp_logo_1_v2.png"
    },
    "fields": [
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 19,
                        "minLength": 12
                    },
                    "luhn": {},
                    "regularExpression": {
                        "regularExpression": "^[0-9]{12,19}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": false,
                "displayOrder": 10,
                "formElement": {
                    "type": "text"
                },
                "label": "Card number",
                "mask": "{{9999}} {{9999}} {{9999}} {{9999}} {{999}}",
                "obfuscate": false,
                "placeholderLabel": "**** **** **** ****",
                "preferredInputType": "IntegerKeyboard"
            },
            "id": "cardNumber",
            "type": "numericstring"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "expirationDate": {},
                    "length": {
                        "maxLength": 4,
                        "minLength": 4
                    },
                    "regularExpression": {
                        "regularExpression": "^(?:0[1-9]|1[0-2])[0-9]{2}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": false,
                "displayOrder": 20,
                "formElement": {
                    "type": "text"
                },
                "label": "Expiry date",
                "mask": "{{99}}/{{99}}",
                "obfuscate": false,
                "placeholderLabel": "MM/YY",
                "preferredInputType": "IntegerKeyboard"
            },
            "id": "expiryDate",
            "type": "expirydate"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 4,
                        "minLength": 3
                    },
                    "regularExpression": {
                        "regularExpression": "^[0-9]{3,4}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": true,
                "displayOrder": 24,
                "formElement": {
                    "type": "text"
                },
                "label": "CVV",
                "mask": "{{9999}}",
                "obfuscate": false,
                "placeholderLabel": "123",
                "preferredInputType": "IntegerKeyboard",
                "tooltip": {
                    "image": "templates/master/global/css/img/ppimages/ppf_cvv_v1.png",
                    "label": "Please enter your security code as shown in the image"
                }
            },
            "id": "cvv",
            "type": "numericstring"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 50,
                        "minLength": 2
                    },
                    "regularExpression": {
                        "regularExpression": "^[-\\sA-Za-z0-9ªºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƒƠơƯưǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǺǻǼǽǾǿȘșȚțΆΈΉΊΌΎΏΑΓΔΕΖΗΙΚΛΝΟΡΣΥΩΪΫάέήίαβγδεζηικλμνξοπρςστυψωϊϋόύώЁЄЇАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяёєїҐґẠạẢảấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹÞþ.'/]+$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": false,
                "displayOrder": 1142,
                "formElement": {
                    "type": "text"
                },
                "label": "Cardholder name",
                "obfuscate": false,
                "placeholderLabel": "John Doe",
                "preferredInputType": "StringKeyboard"
            },
            "id": "cardholderName",
            "type": "string"
        }
    ],
    "id": 1,
    "maxAmount": 1000000,
    "mobileIntegrationLevel": "OPTIMISED_SUPPORT",
    "paymentMethod": "card",
    "paymentProductGroup": "cards",
    "usesRedirectionTo3rdParty": false
}



There is a wide variety of meta data returned for Visa which you can use to display the correct input forms to your consumers; the fields array contains objects with details about which properties are required and how to handle them.

In the above example, you can see that the mandatory properties for Visa are cardNumber, expiryDate, cvv and cardholderName.

Selecting Tokens

As mentioned earlier, you can supply a list of tokens that will be valid for a given session. In this case the response of the GET /client/v1/{customerId}/products or GET /client/v1/{customerId}/products/{paymentProductId}  API call will have an extra accountsOnFile array included per payment product object.

Expand example response

{
    "deviceFingerprintEnabled": true,
    "accountsOnFile": [
        {
            "attributes": [
                {
                    "key": "alias",
                    "value": "************0035",
                    "status": "READ_ONLY"
                },
                {
                    "key": "cardholderName",
                    "value": "Foo Bar",
                    "status": "READ_ONLY"
                },
                {
                    "key": "cardNumber",
                    "value": "************0035",
                    "status": "READ_ONLY"
                },
                {
                    "key": "expiryDate",
                    "value": "1233",
                    "status": "CAN_WRITE"
                }
            ],
            "displayHints": {
                "labelTemplate": [
                    {
                        "attributeKey": "alias",
                        "mask": "{{9999}} {{9999}} {{9999}} {{9999}} {{999}}"
                    }
                ],
                "logo": "templates/master/global/css/img/ppimages/pp_logo_3_v3.png"
            },
            "id": 2,
            "paymentProductId": 3
        },
        {
            "attributes": [
                {
                    "key": "alias",
                    "value": "************5918",
                    "status": "READ_ONLY"
                },
                {
                    "key": "cardholderName",
                    "value": "Foo Bar",
                    "status": "READ_ONLY"
                },
                {
                    "key": "cardNumber",
                    "value": "************5918",
                    "status": "READ_ONLY"
                },
                {
                    "key": "expiryDate",
                    "value": "1233",
                    "status": "CAN_WRITE"
                }
            ],
            "displayHints": {
                "labelTemplate": [
                    {
                        "attributeKey": "alias",
                        "mask": "{{9999}} {{9999}} {{9999}} {{9999}} {{999}}"
                    }
                ],
                "logo": "templates/master/global/css/img/ppimages/pp_logo_3_v3.png"
            },
            "id": 0,
            "paymentProductId": 3
        }
    ],
    "allowsInstallments": false,
    "allowsRecurring": true,
    "allowsTokenization": true,
    "authenticationIndicator": {
        "name": "AUTHENTICATIONINDICATOR",
        "value": "1"
    },
    "autoTokenized": false,
    "displayHints": {
        "displayOrder": 9,
        "label": "MasterCard",
        "logo": "templates/master/global/css/img/ppimages/pp_logo_3_v3.png"
    },
    "fields": [
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 19,
                        "minLength": 12
                    },
                    "luhn": {},
                    "regularExpression": {
                        "regularExpression": "^[0-9]{12,19}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": false,
                "displayOrder": 10,
                "formElement": {
                    "type": "text"
                },
                "label": "Card number",
                "mask": "{{9999}} {{9999}} {{9999}} {{9999}} {{999}}",
                "obfuscate": false,
                "placeholderLabel": "**** **** **** ****",
                "preferredInputType": "IntegerKeyboard"
            },
            "id": "cardNumber",
            "type": "numericstring"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "expirationDate": {},
                    "length": {
                        "maxLength": 4,
                        "minLength": 4
                    },
                    "regularExpression": {
                        "regularExpression": "^(?:0[1-9]|1[0-2])[0-9]{2}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": false,
                "displayOrder": 20,
                "formElement": {
                    "type": "text"
                },
                "label": "Expiry date",
                "mask": "{{99}}/{{99}}",
                "obfuscate": false,
                "placeholderLabel": "MM/YY",
                "preferredInputType": "IntegerKeyboard"
            },
            "id": "expiryDate",
            "type": "expirydate"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 4,
                        "minLength": 3
                    },
                    "regularExpression": {
                        "regularExpression": "^[0-9]{3,4}$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": true,
                "displayOrder": 24,
                "formElement": {
                    "type": "text"
                },
                "label": "CVC2",
                "mask": "{{9999}}",
                "obfuscate": false,
                "placeholderLabel": "123",
                "preferredInputType": "IntegerKeyboard",
                "tooltip": {
                    "image": "templates/master/global/css/img/ppimages/ppf_cvv_{paymentProductId}_v2.png"
                }
            },
            "id": "cvv",
            "type": "numericstring"
        },
        {
            "dataRestrictions": {
                "isRequired": true,
                "validators": {
                    "length": {
                        "maxLength": 50,
                        "minLength": 2
                    },
                    "regularExpression": {
                        "regularExpression": "^[-\\sA-Za-z0-9ªºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƒƠơƯưǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǺǻǼǽǾǿȘșȚțΆΈΉΊΌΎΏΑΓΔΕΖΗΙΚΛΝΟΡΣΥΩΪΫάέήίαβγδεζηικλμνξοπρςστυψωϊϋόύώЁЄЇАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяёєїҐґẠạẢảấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐốỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹÞþ.'/]+$"
                    }
                }
            },
            "displayHints": {
                "alwaysShow": true,
                "displayOrder": 1142,
                "formElement": {
                    "type": "text"
                },
                "label": "Cardholder name",
                "obfuscate": false,
                "placeholderLabel": "John Doe",
                "preferredInputType": "StringKeyboard"
            },
            "id": "cardholderName",
            "type": "string"
        }
    ],
    "id": 3,
    "maxAmount": 1000000,
    "mobileIntegrationLevel": "OPTIMISED_SUPPORT",
    "paymentMethod": "card",
    "paymentProductGroup": "cards",
    "usesRedirectionTo3rdParty": false
}

In the above example, all details for payment product ID 3 have been requested which includes information for 2 tokens.

The attributes array within an individual token object will provide you information to display to the consumer, and whether the fields are editable. Note that any key that matches a mandatory field need not be submitted (unless it has been edited) as it is part of the token.

Encrypted Payload

After the consumer has provided all necessary data, you are ready to go to the encryption step.

While you could implement the next step yourself, we recommend you to use our Client SDKs and the helper utilities to generate the encryptedCustomerInput you need to use to perform the payment.

Pass a payload with all the information that needs to be encrypted to the encryption utility to generate the encryptedCustomerInput.

The payload needs at least the paymentProductId, clientSessionId and nonce properties, with other properties depending on the product. The paymentValues array contains key value pairs for the data required for a particular payment product. For example a card payment’s payload would look like this:


{
    "tokenize": false,
    "paymentProductId": 1,
    "clientSessionId": "52419758a7904941bb73e4dc639b72c7",
    "nonce": "80fc3a40-0670-4b73-b362-745b6f2a2626",
    "paymentValues": [
        {
            "key": "expiryDate",
            "value": "1233"
        },
        {
            "key": "cvv",
            "value": "123"
        },
        {
            "key": "cardholderName",
            "value": "Foo Bar"
        },
        {
            "key": "cardNumber",
            "value": "4111111111111111"
        }
    ]
}

Since card payments can be tokenized, there is an additional tokenize property to request token creation.

Similarly, if you would like to submit a payload that specifies a token to be used, you can süecify the token by setting the accountOnFileId property to the id from the appropriate entry in the accountsOnFile array as shown above:


{
    "paymentProductId": 3,
    "accountOnFileId": 2,
    "clientSessionId": "52419758a7904941bb73e4dc639b72c7",
    "nonce": "80fc3a40-0670-4b73-b362-745b6f2a2626",
    "paymentValues": [
        {
            "key": "cvv",
            "value": "123"
        }
    ]
}

With the encryptedCustomerInput you can now perform a POST /v1/{merchantId}/payments API call with an order object containing an amountOfMoney object and a customer object. The customer object has a lot of options but only the billingAddress object with a countryCode property is required for a basic payment.

The minimum required payload would look like this:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "encryptedCustomerInput": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJraWQiOiJlYmU2Yzc1Yi1lMmNlLTRkOGEtYmUyMi01MmYwMDBkZTY2ZTMifQ.gSrfVdp24Rxfm7141YIoWlVkdXEzZylroY5ASIWiH7EjS_6ak6dpHq7n289IYM2NPrUfO3guIMmYzxbXumUFUzQJnjV4yPQlT8dvgtoSbLGSku4vYxlhWkGpuD0bK8_M1a4QRaQULd-q4N084VmYeOEECDTMwTS46UuDxJdceJ1gkBrTH0SLgFPPYxLVL1tZ0TFqThJs-suBPAuUbBlaI0k3lS8OFnlNit-ABe9PQ_GN9z23HwRwWRYb4F7FFBw6xmmJXWD8cfqHLMojEhQ0i1Tz-17KAURkjKK_SoTY1Fl37ktzStxmgJE66_gR2QVbLak2nsI7GTwuHnTfuWXApQ.Zu7RpXUjtnEUozZSyxiZGw.kdo1xB2aLdGT5Vi4En4fmT8Xvqsx1TiNScF0-caRPr6H1gb971cXT2rmMpEwbKmjTJ-Pp3olts9-ESjxwDEwYd4QirCb9OzWu7zr6JAoWy3rbVcMOBgtZ5QdaOkwVNAlYEWNyroBgmoQBECfUTRNzcfrwftSbYVygYWMNQwUaraJIywEPYHwy7F_PP3npV56k5aLQtKU4oDH6Xn11X5dIcfLeayE0aCFHF_AIufQFGVRTwSjfvz8agDPz3ztaK_3Mn1-Cyj0zBQN492xRDMTKUky68G0w4oFwWn8jcDathpt5-nsGuFrvpwzc4CrHiSkIaMFpZlISuYVvS9Q7n74SfYoiBd53B8x86AZzKAbvNmouIqY7xxlQi5opCziXNIsNyxC-AwmEIKE5nRiwxBh8SFxTNq9DZ9cGGpP96MQSV4.32T2d4BROJ82diyUy6eoOl__U0KSrCSQDbDZ07iXsg0"
}

The encryptedCustomerInput can only be used once; after we have decrypted it and performed a payment, you will receive a 1008 - INVALID_CONSUMER_INPUT error when attempting to use it again.

 

Raw Data

If you wish to handle the card data directly, you can select this option.

After you have securely collected the card data from the consumer, you need to perform a POST /v1/{merchantId}/payments API call, similar to the last step in the Client Encryption option. The difference being that rather than submitting a encryptedCustomerInput property, you need to submit a cardPaymentMethodSpecificInput object.

The payload in this case requires the same order object as described in the last step of 3.1 Client Encryption, and a cardPaymentMethodSpecificInput object. This object needs to contain a paymentProductId property and a card object.

Generally speaking, the card object should contain cardNumber, expiryDate, cvv, and cardholderName properties for a normal one-off payment.

The cardholderName can be different from the name a consumer uses when registering an account. The cardholderName refers to the official name the consumer uses with their issuing bank.

This will result in a payload looking like this:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

You need to be PCI SAQ-D compliant to use this option.

Additional Features

There are several additional features that can be used depending on your needs.

$0 Validation

If you would like to verify whether the card details provided by a consumer are valid even though you are not currently taking a payment, for example if you wish to offer a free trial of a product for an introductory period, you can use $0 Validation (also referred to as Account Verification or $0 Authorization).

This feature is easy to use. You simply need to set the value of the order.amountOfMoney.amount property to 0. This applies for both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

If you perform a $0 Validation via our checkout, the consumer will see it like this:

And on success, they will see this:

If you perform a GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} at this point, you will receive a response like this (it may look different based on your Merchant ID configuration):

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000073740000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "0635145a-7bd2-71ff-8337-68b0d25c9dcb"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 0,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "1484357"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "0",
                        "cvvResult": "0",
                        "microsoftFraudProtection": {
                            "deviceCountryCode": "nl",
                            "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                            "fraudScore": 9,
                            "trueIpAddress": "85.115.33.180",
                            "userDeviceType": "browser_computer"
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1230"
                    }
                }
            },
            "status": "ACCOUNT_VERIFIED",
            "statusOutput": {
                "isCancellable": false,
                "statusCategory": "ACCOUNT_VERIFIED",
                "statusCode": 300,
                "statusCodeChangeDateTime": "20221020145728",
                "isAuthorized": false,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "00000010101000007374",
            "externalReference": "000000101010000073740000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL"
    },
    "status": "PAYMENT_CREATED"
}

 

The response to a POST /v1/{merchantId}/payments API call will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010101000007377",
        "externalReference": "000000101010000073770000100001"
    },
    "payment": {
        "id": "000000101010000073770000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 0,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "36682616"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "0",
                    "cvvResult": "0",
                    "microsoftFraudProtection": {
                        "fraudScore": 24
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                }
            }
        },
        "status": "ACCOUNT_VERIFIED",
        "statusOutput": {
            "isCancellable": false,
            "statusCategory": "ACCOUNT_VERIFIED",
            "statusCode": 300,
            "statusCodeChangeDateTime": "20221021104302",
            "isAuthorized": false,
            "isRefundable": false
        }
    }
}

 

Similarly, a call to the GET /v1/{merchantId}/payments/{paymentId} API will return a response like this:

Expand example response

{
    "id": "000000101010000073770000100001",
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 0,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "36682616"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "0",
                "cvvResult": "0",
                "microsoftFraudProtection": {
                    "fraudScore": 24
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1233"
            }
        }
    },
    "status": "ACCOUNT_VERIFIED",
    "statusOutput": {
        "isCancellable": false,
        "statusCategory": "ACCOUNT_VERIFIED",
        "statusCode": 300,
        "statusCodeChangeDateTime": "20221021104302",
        "isAuthorized": false,
        "isRefundable": false
    }
}

 

As can be seen in the examples, you will receive the special ACCOUNT_VERIFIED status in case of success.

3D Secure

3D Secure is an important subject and is described in detail in this integration guide, so if you wish to know more, detailed information on PSD2, SCA and 3D Secure can be found there.

You can provide a preference of whether to skip 3D or not using the cardPaymentMethodSpecificInput.threeDSecure.skipAuthentication property.

This is the same for both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

Alternatively, you could use Dynamic 3D Secure to set this parameter for you depending on what rules are configured, in that case, you should not submit this property.

Even if you set cardPaymentMethodSpecificInput.threeDSecure.skipAuthentication to true, our SmartComply service may determine that skipping 3D Secure is not allowed in the current PSD2 context, in which case we will continue with 3D Secure to meet SCA requirements.

A successful 3D Secure v2 authentication requires information to be provided about the consumer browser. If you use our checkout we will collect any required browser details. If you use the POST /v1/{merchantId}/paymentsAPI call then you will need to submit a few mandatory properties regarding the consumer using the order.customer.device object.

Here is an example of the device object with all the necessary properties for 3D Secure v2 provided:


            "device": {
                "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "browserData": {
                    "colorDepth": 24,
                    "innerHeight": 326,
                    "innerWidth": 779,
                    "javaEnabled": true,
                    "javaScriptEnabled": true,
                    "screenHeight": 1305,
                    "screenWidth": 3116
                },
                "ipAddress": "185.219.197.244",
                "locale": "en_US",
                "timezoneOffsetUtcMinutes": "60",
                "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
            }

Our Client SDK also provides utility methods to gather most of these properties.

There are a few extra mandatory properties in the cardPaymentMethodSpecificInput object.

We mentioned earlier that it is recommended to submit the cardholderName property. This is because it is a mandatory property for 3D Secure v2.

Lastly, you will also need to submit the cardPaymentMethodSpecificInput.threeDSecure.redirectionData.returnUrl property with the URL where you wish the consumer to be redirected to after the payment.

Putting all of this together results in a payload that looks like this:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            },
            "device": {
                "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
                "browserData": {
                    "colorDepth": 24,
                    "innerHeight": 326,
                    "innerWidth": 779,
                    "javaEnabled": true,
                    "javaScriptEnabled": true,
                    "screenHeight": 1305,
                    "screenWidth": 3116
                },
                "ipAddress": "185.219.197.244",
                "locale": "en_US",
                "timezoneOffsetUtcMinutes": "60",
                "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        },
        "threeDSecure": {
            "skipAuthentication": false,
            "redirectionData": {
                "returnUrl": "https://example.org/return"
            }
        }
    }
}

If 3D Secure is determined to be required, there will be a few flows the consumer can go through:

  • Frictionless
  • Frictionless with Method URL
  • Challenge
  • Challenge with Method URL

In case of Frictionless, there is no additional action needed. In all other cases, we will return a merchantAction object. There are various different actionType values but in the case of 3D Secure, we will always return the actionType value REDIRECT. This is accompanied with a redirectData object that contains a redirectURL that you need to direct your consumer to in order for them to complete the 3D Secure authentication.

Be aware that the merchantAction is only returned in the response to POST /v1/{merchantId}/payments and will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010100000002482",
        "externalReference": "000000101000000024820000100001"
    },
    "merchantAction": {
        "actionType": "REDIRECT",
        "redirectData": {
            "RETURNMAC": "296823ee-c9ee-4be1-a391-c9f282e04e5a",
            "redirectURL": "https://payment.rpp-cdn.int.test.igdcs.com/3dsecure/e90a1320-874b-4101-ba51-e5b418d12ba6"
        }
    },
    "payment": {
        "id": "000000101000000024820000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "0"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "threeDSecureResults": {
                    "authenticationAmount": {
                        "amount": 100,
                        "currencyCode": "SEK"
                    },
                    "exemptionOutput": {
                        "exemptionRaised": "none",
                        "exemptionRequest": "none"
                    },
                    "threeDSecureVersion": "2.2.0",
                    "threeDServerTransactionId": "5f677ddc-a75b-44a2-9514-9b7be8f6573a"
                },
                "card": {
                    "cardNumber": "401200******9936",
                    "cardholderName": "Foo Bar",
                    "expiryDate": "1233"
                }
            }
        },
        "status": "REDIRECTED",
        "statusOutput": {
            "isCancellable": false,
            "statusCategory": "PENDING_PAYMENT",
            "statusCode": 50,
            "statusCodeChangeDateTime": "20221101154227",
            "isAuthorized": false,
            "isRefundable": false,
            "threeDSecureStatus": "ENROLLED"
        }
    }
}

 

The merchantAction is omitted from the GET /v1/{merchantId}/payments/{paymentId} API call and will return a response like this:

Expand example response

{
    "id": "000000101000000024820000100001",
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "0"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "threeDSecureResults": {
                "authenticationAmount": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "exemptionOutput": {
                    "exemptionRaised": "none",
                    "exemptionRequest": "none"
                },
                "threeDSecureVersion": "2.2.0",
                "threeDServerTransactionId": "5f677ddc-a75b-44a2-9514-9b7be8f6573a"
            },
            "card": {
                "cardNumber": "401200******9936",
                "cardholderName": "Foo Bar",
                "expiryDate": "1233"
            }
        }
    },
    "status": "REDIRECTED",
    "statusOutput": {
        "isCancellable": false,
        "statusCategory": "PENDING_PAYMENT",
        "statusCode": 50,
        "statusCodeChangeDateTime": "20221101154227",
        "isAuthorized": false,
        "isRefundable": false,
        "threeDSecureStatus": "ENROLLED"
    }
}

 

Further information on other properties related to 3D Secure that were not covered can be found here.

Address Verification

In order to use Address Verification, you need to contact us to request for this feature to be enabled on your Merchant ID.

To use this feature, you need to send the address and ZIP code in the order.customer.billingAddress.


{
    "order": {
        "amountOfMoney": {
            "amount": 0,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL",
                "houseNumber": "1",
                "street": "Hoofdstraat",
                "zip": "AAAA00"
            }
        }
    }
}

This works the same way in both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

You will be able to find the result in the cardPaymentMethodSpecificOutput.fraudResults.avsResult property.

Here is an example of the output of GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} (it may look different based on your Merchant ID configuration):

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000073880000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "063528f1-7c36-71ff-9c74-ba3461283eff"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "42319254"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "X",
                        "cvvResult": "M",
                        "microsoftFraudProtection": {
                            "deviceCountryCode": "nl",
                            "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                            "fraudScore": 5,
                            "trueIpAddress": "85.115.33.180",
                            "userDeviceType": "browser_computer"
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1230"
                    }
                }
            },
            "status": "PENDING_APPROVAL",
            "statusOutput": {
                "isCancellable": true,
                "statusCategory": "PENDING_MERCHANT",
                "statusCode": 600,
                "statusCodeChangeDateTime": "20221021142305",
                "isAuthorized": true,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "00000010101000007388",
            "externalReference": "000000101010000073880000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL"
    },
    "status": "PAYMENT_CREATED"
}

 

The response to POST /v1/{merchantId}/payments will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010101000007389",
        "externalReference": "000000101010000073890000100001"
    },
    "payment": {
        "id": "000000101010000073890000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "58862045"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "X",
                    "cvvResult": "M",
                    "microsoftFraudProtection": {
                        "fraudScore": 11
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                }
            }
        },
        "status": "PENDING_APPROVAL",
        "statusOutput": {
            "isCancellable": true,
            "statusCategory": "PENDING_MERCHANT",
            "statusCode": 600,
            "statusCodeChangeDateTime": "20221021143255",
            "isAuthorized": true,
            "isRefundable": false
        }
    }
}

 

Similarly, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:

Expand example response

{
    "id": "000000101010000073890000100001",
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "58862045"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "X",
                "cvvResult": "M",
                "microsoftFraudProtection": {
                    "fraudScore": 11
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1233"
            }
        }
    },
    "status": "PENDING_APPROVAL",
    "statusOutput": {
        "isCancellable": true,
        "statusCategory": "PENDING_MERCHANT",
        "statusCode": 600,
        "statusCodeChangeDateTime": "20221021143255",
        "isAuthorized": true,
        "isRefundable": false
    }
}

 

In the example responses above, the avsResult is returned as X which means that it was a perfect match.

For a full list of possible responses, please refer to this page.

This is purely informational as not all issuers support this feature so at times you may not receive a valid response.

Authorization Types

Changing the authorization type changes the behavior for both the consumer and for you as merchant.

From a consumer’s perspective, what changes is how long the authorization is valid for. While it can differ based on scheme and industry, the general characteristics are:

  • Pre-authorizations are valid for ±30 days, you may capture an amount lower than authorized, and you can perform the capture at any time during the authorization period.
  • Final authorizations are valid for ±7 days, you must capture the exact amount authorized, and you can perform the capture at any time during the authorization period.
  • Sale authorizations are captured immediately.

The optional property authorizationMode in the cardPaymentMethodSpecificInput object can be used to set the type of authorization you are sending. This applies to both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

The valid values are FINAL_AUTHORIZATION, PRE_AUTHORIZATION, or SALE.

An example of how to set the property for the POST /v1/{merchantId}/payments API call:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "authorizationMode": "PRE_AUTHORIZATION",
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

However, as also mentioned in the API Reference, support for this feature varies depending on which acquirer is configured for your Merchant ID. Because of this, we recommended that you contact us to request that we set authorization type as a fixed setting on your Merchant ID.

As mentioned earlier, a characteristic of the Final- and Pre-Authorizations (either through the API or via configuration) is that you can choose when to capture. 

Text about requiresApproval for WOPA.

If you do choose to send it in the request, it should look like this:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "authorizationMode": "PRE_AUTHORIZATION",
        "requiresApproval": true,
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

The response to POST /v1/{merchantId}/payments (it may look different based on your Merchant ID configuration) would look like:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010101000007393",
        "externalReference": "000000101010000073930000100001"
    },
    "payment": {
        "id": "000000101010000073930000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "75242216"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "0",
                    "cvvResult": "0",
                    "microsoftFraudProtection": {
                        "fraudScore": 14
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                }
            }
        },
        "status": "PENDING_APPROVAL",
        "statusOutput": {
            "isCancellable": true,
            "statusCategory": "PENDING_MERCHANT",
            "statusCode": 680,
            "statusCodeChangeDateTime": "20221021155348",
            "isAuthorized": true,
            "isRefundable": false
        }
    }
}

 

Similarly, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:

Expand example response

{
    "id": "000000101010000073930000100001",
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "75242216"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "0",
                "cvvResult": "0",
                "microsoftFraudProtection": {
                    "fraudScore": 14
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1233"
            }
        }
    },
    "status": "PENDING_APPROVAL",
    "statusOutput": {
        "isCancellable": true,
        "statusCategory": "PENDING_MERCHANT",
        "statusCode": 680,
        "statusCodeChangeDateTime": "20221021155348",
        "isAuthorized": true,
        "isRefundable": false
    }
}

 

And here is how the equivalent GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId}:

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000073950000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "06352a55-b0ea-71ff-8ee1-74df8590db6f"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "77307321"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "X",
                        "cvvResult": "M",
                        "microsoftFraudProtection": {
                            "deviceCountryCode": "nl",
                            "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                            "fraudScore": 5,
                            "trueIpAddress": "85.115.33.180",
                            "userDeviceType": "browser_computer"
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1230"
                    }
                }
            },
            "status": "PENDING_APPROVAL",
            "statusOutput": {
                "isCancellable": true,
                "statusCategory": "PENDING_MERCHANT",
                "statusCode": 680,
                "statusCodeChangeDateTime": "20221021155804",
                "isAuthorized": true,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "00000010101000007395",
            "externalReference": "000000101010000073950000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL"
    },
    "status": "PAYMENT_CREATED"
}

 

As can be seen above, the status will be changed to PENDING_APPROVAL (as opposed to CAPTURE_REQUESTED which is the usual status of a successful card payment) which indicates that it is waiting for your approval to continue.

In order to instruct us to perform the capture, you need to send the approval with the POST /v1/{merchantId}/payments/{paymentId}/approve API call.

In case of a Pre-authorization, this API call is also used to modify the amount to be captured, in order to set an amount, simply submit the amount property with any value lower than the original authorization amount.

The payload should look like this:


{
    "amount": 50
}

After we receive your approval to capture, we will proceed with the transaction after which the status will change to CAPTURE_REQUESTED.

Credential on File

The Credential on File (also known as COF) framework can be a bit complicated to use due to differences between different schemes, but in short, this enables you to offer consumers to store their card details for future use. Depending on PCI compliance level, you can either let us store the card details, or store them yourself.

We will focus on 2 major use-cases:

  1. Recurring
  2. Unscheduled Credential on File (UCOF)

Recurring is used when you need to do fixed cycle subscription payments (e.g. your monthly music streaming service). UCOF can be further split up into 2 use-cases; the first is when you offer your consumers to save the card details so that on a future order, the consumer can just select it from a list, the second is when you need to charge the consumer on an irregular schedule such as an automatic top-up service where you need to make a charge if the consumer’s balance hits a certain threshold.

Recurring

To initiate a new sequence of Recurring payments you need to submit the first request with a few extra properties in cardPaymentMethodSpecificInput. By setting the isRecurring property to true, the transaction will be considered Recurring. The characteristics will be provided in the recurring object which contains the endDate, minFrequency and recurringPaymentSequenceIndicator properties.

Note that in contrast to many other features described here, this does not work exactly the same way for the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

The difference is that the isRecurring property will need to be submitted in the hostedCheckoutSpecificInput object instead of the cardPaymentMethodSpecificInput when using hostedcheckouts.

This is the example payload for the POST /v1/{merchantId}/hostedcheckouts API call:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "recurring": {
            "endDate": 20301231,
            "minFrequency": 30,
            "recurringPaymentSequenceIndicator": "first"
        }
    },
    "hostedCheckoutSpecificInput": {
        "isRecurring": true
    }
}

And this is how it would look like for the POST /v1/{merchantId}/payments API call:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        },
        "isRecurring": true,
        "recurring": {
            "endDate": 20301231,
            "minFrequency": 30,
            "recurringPaymentSequenceIndicator": "first"
        }
    }
}

Here is an example of the output of GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} (it may look different based on your Merchant ID configuration):

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000074310000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "06359243-66db-71ff-8f99-f21b5dcf85c3"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "96375930"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "0",
                        "cvvResult": "0",
                        "microsoftFraudProtection": {
                            "fraudScore": 7
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1230"
                    },
                    "schemeTransactionId": "000000000004034"
                }
            },
            "status": "PENDING_APPROVAL",
            "statusOutput": {
                "isCancellable": true,
                "statusCategory": "PENDING_MERCHANT",
                "statusCode": 600,
                "statusCodeChangeDateTime": "20221026141451",
                "isAuthorized": true,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "01010100000743100001",
            "externalReference": "0101010000074310000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL",
        "tokenizationSucceeded": true,
        "tokens": "dab1549d-cbb1-4044-968a-b1c520eb8525"
    },
    "status": "PAYMENT_CREATED"
}

 

Similarly, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:

Expand example response

{
    "id": "000000101010000074310000100001",
    "hostedCheckoutSpecificOutput": {
        "hostedCheckoutId": "06359243-66db-71ff-8f99-f21b5dcf85c3"
    },
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "96375930"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "0",
                "cvvResult": "0",
                "microsoftFraudProtection": {
                    "fraudScore": 7
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1230"
            },
            "schemeTransactionId": "000000000004034"
        }
    },
    "status": "PENDING_APPROVAL",
    "statusOutput": {
        "isCancellable": true,
        "statusCategory": "PENDING_MERCHANT",
        "statusCode": 600,
        "statusCodeChangeDateTime": "20221026141451",
        "isAuthorized": true,
        "isRefundable": false
    }
}

 

The response to POST /v1/{merchantId}/payments will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "01010100000743200001",
        "externalReference": "0101010000074320000100001",
        "isNewToken": false,
        "token": "dab1549d-cbb1-4044-968a-b1c520eb8525",
        "tokenizationSucceeded": true
    },
    "payment": {
        "id": "000000101010000074320000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "77894183"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "0",
                    "cvvResult": "0",
                    "microsoftFraudProtection": {
                        "fraudScore": 14
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                },
                "schemeTransactionId": "000000000004035"
            }
        },
        "status": "PENDING_APPROVAL",
        "statusOutput": {
            "isCancellable": true,
            "statusCategory": "PENDING_MERCHANT",
            "statusCode": 600,
            "statusCodeChangeDateTime": "20221026141714",
            "isAuthorized": true,
            "isRefundable": false
        }
    }
}

 

You need to store the schemeTransactionId value from the response to be able to correctly perform subsequent payments; this value needs to be submitted in all future API calls that belong to this same sequence of recurring payments.

For recurring payments we will also return a token or tokens property. In case you are not PCI SAQ-D compliant, you will need to use the token for future payments as you cannot store the credentials yourself. For further information regarding tokenization, please refer to this page.

In order to initiate a subsequent payment in the recurring sequence, you need to perform a POST /v1/{merchantId}/payments API call with the initialSchemeTransactionId property containing the value of the schemeTransactionId you previously stored, and either the token or the card data (excluding the Card Security Code since there is no consumer to provide it).

This is an example payload using a token:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "token": "dab1549d-cbb1-4044-968a-b1c520eb8525",
        "isRecurring": true,
        "recurring": {
            "recurringPaymentSequenceIndicator": "recurring"
        },
        "initialSchemeTransactionId": "000000000004035"
    }
}

And this is how it would look with the card details:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        },
        "isRecurring": true,
        "recurring": {
            "recurringPaymentSequenceIndicator": "recurring"
        },
        "initialSchemeTransactionId": "000000000004059"
    }
}
UCOF

UCOF, in a similar way to Recurring, needs you to perform a first transaction, which will return a schemeTransactionId that you need to submit in future UCOF transactions for the same sequence.

In order to perform any UCOF transaction, you need to submit the unscheduledCardOnFileRequestor and unscheduledCardOnFileSequenceIndicator properties within the cardPaymentMethodSpecificInput object, and the merchantCustomerId in the customer object.

To indicate that it is the first payment, you need to set unscheduledCardOnFileRequestor to cardholderInitiated and unscheduledCardOnFileSequenceIndicator to first. The value of the merchantCustomerId corresponds to the identifier you use internally to identify a consumer.

This is how a POST /v1/{merchantId}/payments payload would look:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "merchantCustomerId": "10011011101000",
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        },
        "unscheduledCardOnFileRequestor": "cardholderInitiated",
        "unscheduledCardOnFileSequenceIndicator": "first"
    }
}

UCOF, in contrast to Recurring, does not need you to submit any additional properties within the hostedCheckoutSpecificInput object in order to perform a first transaction for the POST /v1/{merchantId}/hostedcheckouts API call. Here is an example payload:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "merchantCustomerId": "10011011101000",
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "unscheduledCardOnFileRequestor": "cardholderInitiated",
        "unscheduledCardOnFileSequenceIndicator": "first"
    }
}

The response will be similar to the response for an initial recurring payment and will contain a schemeTransactionId.

Example of the output of GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} (it may look different based on your Merchant ID configuration):

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000074590000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "0635bc96-d153-71ff-a1ad-2a9ebe878140"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "39944275"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "0",
                        "cvvResult": "0",
                        "microsoftFraudProtection": {
                            "deviceCountryCode": "nl",
                            "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                            "fraudScore": 6,
                            "trueIpAddress": "85.115.33.180",
                            "userDeviceType": "browser_computer"
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1233"
                    },
                    "schemeTransactionId": "000000000004479"
                }
            },
            "status": "PENDING_APPROVAL",
            "statusOutput": {
                "isCancellable": true,
                "statusCategory": "PENDING_MERCHANT",
                "statusCode": 600,
                "statusCodeChangeDateTime": "20221028142228",
                "isAuthorized": true,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "00000010101000007459",
            "externalReference": "000000101010000074590000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL",
        "tokenizationSucceeded": true,
        "tokens": "dab1549d-cbb1-4044-968a-b1c520eb8525"
    },
    "status": "PAYMENT_CREATED"
}

 

Similarly, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:

Expand example response

{
    "id": "000000101010000074590000100001",
    "hostedCheckoutSpecificOutput": {
        "hostedCheckoutId": "0635bc96-d153-71ff-a1ad-2a9ebe878140"
    },
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "39944275"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "0",
                "cvvResult": "0",
                "microsoftFraudProtection": {
                    "deviceCountryCode": "nl",
                    "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                    "fraudScore": 6,
                    "trueIpAddress": "85.115.33.180",
                    "userDeviceType": "browser_computer"
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1233"
            },
            "schemeTransactionId": "000000000004479"
        }
    },
    "status": "PENDING_APPROVAL",
    "statusOutput": {
        "isCancellable": true,
        "statusCategory": "PENDING_MERCHANT",
        "statusCode": 600,
        "statusCodeChangeDateTime": "20221028142228",
        "isAuthorized": true,
        "isRefundable": false
    }
}

 

The response to POST /v1/{merchantId}/payments will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010101000007460",
        "externalReference": "000000101010000074600000100001",
        "isNewToken": false,
        "token": "dab1549d-cbb1-4044-968a-b1c520eb8525",
        "tokenizationSucceeded": true
    },
    "payment": {
        "id": "000000101010000074600000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "21610305"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "0",
                    "cvvResult": "0",
                    "microsoftFraudProtection": {
                        "fraudScore": 19
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                },
                "schemeTransactionId": "000000000004480"
            }
        },
        "status": "PENDING_APPROVAL",
        "statusOutput": {
            "isCancellable": true,
            "statusCategory": "PENDING_MERCHANT",
            "statusCode": 600,
            "statusCodeChangeDateTime": "20221028142315",
            "isAuthorized": true,
            "isRefundable": false
        }
    }
}

 

You now have the schemeTransactionId and the token (if you need it) for potential future UCOF transactions.

Here is an overview of the valid value combinations for unscheduledCardOnFileRequestor and unscheduledCardOnFileSequenceIndicator:

Requestor \ Indicator cardholderInitiated merchantInitiated
first ✔️
subsequent ✔️ ✔️

 

In order to perform the first transaction, the combination first and cardholderInitiated were used. Two other valid combinations remain:

  • subsequent with cardholderInitiated
  • subsequent with merchantInitiated

These cover 2 different use-cases mentioned earlier.

When you send subsequent with cardholderInitiated, you do not need to submit the initialSchemeTransactionId property, but the consumer must enter their Card Security Code. This option is used, for example, when the consumer is going through the checkout on your website and they wish to use the card details that they had previously stored with you (or us if you use tokens). If you do use our tokens, you can submit a list of tokens under the hostedCheckoutSpecificInput object in the POST /v1/{merchantId}/hostedcheckouts API call to present a list of stored card details to consumers:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "merchantCustomerId": "10011011101000",
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "unscheduledCardOnFileRequestor": "cardholderInitiated",
        "unscheduledCardOnFileSequenceIndicator": "subsequent"
    },
    "hostedCheckoutSpecificInput": {
        "tokens": "dab1549d-cbb1-4044-968a-b1c520eb8525, fe0a56f7-911c-430b-8147-358dded93a15"
    }
}

Which will be shown to the consumer as such:

When you send subsequent and merchantInitiated, you do need to submit the initialSchemeTransactionId (with the value from the schemeTransactionId property from the first transaction), but the Card Security Code is not used. This option is used, for example, when you need to perform automatic balance top-ups without consumer interaction.

Example payload for the POST /v1/{merchantId}/payments API call in case you store the card details:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "merchantCustomerId": "10011011101000",
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        },
        "unscheduledCardOnFileRequestor": "merchantInitiated",
        "unscheduledCardOnFileSequenceIndicator": "subsequent",
        "initialSchemeTransactionId": "000000000004480"
    }
}

And a version in case we store the card details:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "merchantCustomerId": "10011011101000",
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "token": "dab1549d-cbb1-4044-968a-b1c520eb8525",
        "unscheduledCardOnFileRequestor": "merchantInitiated",
        "unscheduledCardOnFileSequenceIndicator": "subsequent",
        "initialSchemeTransactionId": "000000000004480"
    }
}

You need to submit all the details necessary for 3D Secure the initial transaction for both Recurring and UCOF to ensure that 3D Secure v2 can be performed if necessary.

Card Security Code

This refers to the 3 (or 4 in case of American Express) on the back of the card (also known as CVV, CVC, CID, or CAV). This is mandatory for all transactions that were initiated with the cardholder present, with the exception being MOTO as there it is technically not the cardholder entering their card details.

In the case of POST /v1/{merchantId}/hostedcheckouts, the consumer will enter it directly on our checkout.

For POST /v1/{merchantId}/payments, it needs to be submitted via the cardPaymentMethodSpecificInput.card.cvv property, this can be done as such:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

You are not allowed to store the Card Security Code. This is always the case, even if you are PCI SAQ-D compliant.

Alternatively, if you make use of the encryptedCustomerInput as mentioned in the Client Encryption section, then you do not need to submit it as it is already part of encrypted payload.

The result of the CSC check will be returned in the cardPaymentMethodSpecificOutput.fraudResults.cvvResult property.

Here is an example of the output of GET /v1/{merchantId}/hostedcheckouts/{hostedCheckoutId} (it may look different based on your Merchant ID configuration):

Expand example response

{
    "createdPaymentOutput": {
        "payment": {
            "id": "000000101010000073880000100001",
            "hostedCheckoutSpecificOutput": {
                "hostedCheckoutId": "063528f1-7c36-71ff-9c74-ba3461283eff"
            },
            "paymentOutput": {
                "amountOfMoney": {
                    "amount": 100,
                    "currencyCode": "SEK"
                },
                "references": {
                    "paymentReference": "0",
                    "providerId": "3500",
                    "providerReference": "42319254"
                },
                "paymentMethod": "card",
                "cardPaymentMethodSpecificOutput": {
                    "paymentProductId": 1,
                    "authorisationCode": "HOSTOK",
                    "fraudResults": {
                        "fraudServiceResult": "accepted",
                        "avsResult": "X",
                        "cvvResult": "M",
                        "microsoftFraudProtection": {
                            "deviceCountryCode": "nl",
                            "deviceId": "0a625c1803ce09c13e4d7d228efe7c3ae36243019a827ed7e2207aa765a3096c",
                            "fraudScore": 5,
                            "trueIpAddress": "85.115.33.180",
                            "userDeviceType": "browser_computer"
                        }
                    },
                    "card": {
                        "cardNumber": "411111******1111",
                        "expiryDate": "1230"
                    }
                }
            },
            "status": "PENDING_APPROVAL",
            "statusOutput": {
                "isCancellable": true,
                "statusCategory": "PENDING_MERCHANT",
                "statusCode": 600,
                "statusCodeChangeDateTime": "20221021142305",
                "isAuthorized": true,
                "isRefundable": false
            }
        },
        "paymentCreationReferences": {
            "additionalReference": "00000010101000007388",
            "externalReference": "000000101010000073880000100001"
        },
        "paymentStatusCategory": "SUCCESSFUL"
    },
    "status": "PAYMENT_CREATED"
}

 

The response to POST /v1/{merchantId}/payments will look like this:

Expand example response

{
    "creationOutput": {
        "additionalReference": "00000010101000007389",
        "externalReference": "000000101010000073890000100001"
    },
    "payment": {
        "id": "000000101010000073890000100001",
        "paymentOutput": {
            "amountOfMoney": {
                "amount": 100,
                "currencyCode": "SEK"
            },
            "references": {
                "paymentReference": "0",
                "providerId": "3500",
                "providerReference": "58862045"
            },
            "paymentMethod": "card",
            "cardPaymentMethodSpecificOutput": {
                "paymentProductId": 1,
                "authorisationCode": "HOSTOK",
                "fraudResults": {
                    "fraudServiceResult": "accepted",
                    "avsResult": "X",
                    "cvvResult": "M",
                    "microsoftFraudProtection": {
                        "fraudScore": 11
                    }
                },
                "card": {
                    "cardNumber": "411111******1111",
                    "expiryDate": "1233"
                }
            }
        },
        "status": "PENDING_APPROVAL",
        "statusOutput": {
            "isCancellable": true,
            "statusCategory": "PENDING_MERCHANT",
            "statusCode": 600,
            "statusCodeChangeDateTime": "20221021143255",
            "isAuthorized": true,
            "isRefundable": false
        }
    }
}

 

Similarly, GET /v1/{merchantId}/payments/{paymentId} will return a response like this:

Expand example response

{
    "id": "000000101010000073890000100001",
    "paymentOutput": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "references": {
            "paymentReference": "0",
            "providerId": "3500",
            "providerReference": "58862045"
        },
        "paymentMethod": "card",
        "cardPaymentMethodSpecificOutput": {
            "paymentProductId": 1,
            "authorisationCode": "HOSTOK",
            "fraudResults": {
                "fraudServiceResult": "accepted",
                "avsResult": "X",
                "cvvResult": "M",
                "microsoftFraudProtection": {
                    "fraudScore": 11
                }
            },
            "card": {
                "cardNumber": "411111******1111",
                "expiryDate": "1233"
            }
        }
    },
    "status": "PENDING_APPROVAL",
    "statusOutput": {
        "isCancellable": true,
        "statusCategory": "PENDING_MERCHANT",
        "statusCode": 600,
        "statusCodeChangeDateTime": "20221021143255",
        "isAuthorized": true,
        "isRefundable": false
    }
}

 

The examples show an M result which means that the provided CSC is correct, other possible responses can be found here.

While by default this is mandatory for cardholder present transactions, if there is a valid business case for you to make this optional, please contact us so that we can evaluate your specific use-case.

Lastly, it is important to note that cvv property is not used for the South Korean local cards (paymentProductIds 180, 181, 182, 183, 184, 185 and 186). Instead, those use the partialPin property. All recommendations for cvv also apply to partialPin which fulfills the same role and is also submitted in the same manner:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "KRW"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "KR"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 186,
        "card": {
            "partialPin": "12",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233"
        }
    }
}

There is no equivalent to the cvvResult response property for partialPin.

Descriptor

The Descriptor feature (also known as Soft Descriptor or Dynamic Descriptor) allows you to customize what is shown on the consumer’s card statement. By default, it will show your name as provided to us during the Boarding Process, but the descriptor property will allow you to override this.

This property needs to be submitted within the references object which is part of the order object. This applies to both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

An example of how to submit the descriptor is as follows:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        },
        "references": {
            "descriptor": "Anaheim Electronics v45601"
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

The submitted descriptor will not be returned in any of the response objects.

The descriptor property itself allows for quite a few characters to be submitted, but as the various acquirers that we support maintain different character limits, the general recommendation is to send no more than 22 characters. If you send more characters than happens to be supported by the acquirer configured on your Merchant ID, we will truncate the value.

Installments

If you wish to offer your consumers the option to pay in installments, that is possible, additional information on installments can be found here.

You need to submit an installments object within the order.additionalInput object. The properties are the same for both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

An example of how the installments object needs to look like:


        "additionalInput": {
            "installments": {
                "frequencyOfInstallments": "monthly",
                "interestRate": "10.75",
                "numberOfInstallments": 10,
                "amountOfMoneyPerInstallment": {
                    "amount": 10,
                    "currencyCode": "BRL"
                }
            }
        }

In case you use our checkout, this is how it will be shown to the consumer:

We do not perform extra validation on the submitted values, we use the values as-is.

Mail Order/Telephone Order

In case you wish to accept card payments through Mail Order/Telephone (also known as MOTO), you need to ensure that you adjust the transactionChannel.

The transactionChannel can be send within the cardPaymentMethodSpecificInput object. This applies to both the POST /v1/{merchantId}/hostedcheckouts and POST /v1/{merchantId}/payments API calls.

The valid values are ECOMMERCE, MAIL, MOTO, or TELEPHONE where the default is set to ECOMMERCE when the property is not submitted.

MAIL and TELEPHONE are the preferred values but if you end up in a situation where it could be either then MOTO is fine to use.

The transaction channel is not returned in the response so you only need to take care of the request, here is an example of the payload:


{
    "order": {
        "amountOfMoney": {
            "amount": 100,
            "currencyCode": "SEK"
        },
        "customer": {
            "billingAddress": {
                "countryCode": "NL"
            }
        }
    },
    "cardPaymentMethodSpecificInput": {
        "paymentProductId": 1,
        "transactionChannel": "MOTO",
        "card": {
            "cvv": "123",
            "cardNumber": "4111111111111111",
            "expiryDate": "1233",
            "cardholderName": "Foo Bar"
        }
    }
}

As an alternative, we also offer a service that can be used to facilitate this called LinkPlus, this will provide a card details input screen and handle the transactionChannel setting.

Refunds and Reversals

If you wish to cancel a payment, you have 2 opportunities to do so; before the capture and after the capture, depending on the situation, you need to send a separate API call.

The first one we will cover is POST /v1/{merchantId}/payments/{paymentId}/cancel, cancelling a transaction refers reversing an authorization hold on the card.

This can be performed in the following situations:

  • The status is PENDING_APPROVAL and statusOutput.isCancellable is true
  • The status is CAPTURE_REQUESTED and statusOutput.isCancellable is true

Depending on which acquirer your Merchant ID has been configured with, the consumer might not see an immediate release of the authorization hold if the configured acquirer does not support this feature.

If you set the requiresApproval property to true (as mentioned in the Credential on File section), there is also a way to undo the approval. In case you mistakenly called POST /v1/{merchantId}/payments/{paymentId}/approve, you may use the POST /v1/{merchantId}/payments/{paymentId}/cancelapproval API call to revert the transaction back to the PENDING_APPROVAL status.

Next is the POST /v1/{merchantId}/payments/{paymentId}/refund API call, this is only possible in 1 situation; if status is CAPTURE_REQUESTED and statusOutput.isCancellable is false.

You may refund any amount equal or lower to the captured amount, and may do this up till the total captured amount has been refunded.

A basic refund payload only requires the amountOfMoney object specifying the amount and currencyCode:


{
    "amountOfMoney": {
        "amount": 25,
        "currencyCode": "SEK"
    }
}

If you wish to see the details of your refund, you may use the GET /v1/{merchantId}/refunds/{refundId} API call.

Similar to payments, refunds also have an approval mechanism, the difference is that for refunds this is a fixed setting whereas payments had the option to send the requiresApproval property. If you have requested us to configure your Merchant ID with this setting for refunds, you can use the POST /v1/{merchantId}/refunds/{refundId}/approve API call in a similar fashion as the one for payments.

Refunds can also be cancelled, the conditions are the same as for payments, but instead of CAPTURE_REQUESTED, the status needs to be REFUND_REQUESTED instead. The usage of /v1/{merchantId}/refunds/{refundId}/cancel is similar to the payments equivalent.

 

Local Property Requirements for the Brazil market

Individual Purchase (Merchant selling to an individual end user)
  Property Example Required
1 order.references.merchantReference ABcd1234567 R
2 order.customer.contactDetails.emailAddress "johndoe@gmail.com" M
  order.customer.personalInformation.name.firstName "John"  
3 order.customer.personalInformation.name.surname "Doe" M
4 order.customer.billingAddress.BirthDate (Individual"s birth date) 1980-09-07 O
5 order.customer.fiscalNumber (CPF number)
The CPF is the Tax ID for an individual in Brazil. It consists of an 11 digits
The CPF number has different sections and the last 2 digits are used to verify (double-check) if the number provided is accurate and correct.
12345678901 M
6 order.customer.billingAddress.street AV MIRACATU M
7 order.customer.billingAddress.houseNumber 1234 M
8 order.customer.billingAddress.AddressLine3 (Street Compliment "example: Apartment Number, PO Box) CJ 5 O
Required, if exists
9 order.customer.billingAddress.city CURITIBA M
10 order.customer.billingAddress.stateCode PR M
11 order.customer.billingAddress.zip 81500000 M
12 order.customer.billingAddress.countryCode br M
13 order.customer.billingAddress.mobilePhoneNumber - Numbers can be up to 15 characters long, minimum 8 digits (without including the area code). 1234567890 M
14 order.amountOfMoney.amount - Minimum Auth amount is 1 BRL." For Installment transactions, send total amount of order. 10000 M
15 order.amountOfMoney.currencyCode (BRL, EUR, USD) BRL M
16 DueDate (Optional field used for Boleto"s only. If this field is not populated, the default is 4 days. If field is populated, it must be within 1 " 7 days of issued date) 2014-04-17 O
17 paymentMethodSpecificInput.paymentProductId
e.g. Cards - 147 (ELO), Redirect - 6105 (Pix), Cash - 1503 (Boleto)
6105 M
O (hostedCheckouts)
18 AdditionalOrderInput.installments.installmentPlanCode (Optional field that should only be used when customer wants to pay using Installments with a credit card. 51 O
For Credit Cards

 

Property

Example

Requirement

19

cardPaymentMethodSpecificInput.card.CardNumber

4111111111111111

M

20

cardPaymentMethodSpecificInput.card.ExpirationDate

2016-12

M

21

cardPaymentMethodSpecificInput.card.cvv

123

M/O

22

cardPaymentMethodSpecificInput.RecurringIndicator (NOT_RECURRING = not a recurring transaction, FIRST_RECURRING = first transaction that will have future recurring transactions, SUBSEQUENT_RECURRING = each transaction after the FIRST_RECURRING transaction

"NOT_RECURRING", "FIRST_RECURRING" or

"SUBSEQUENT

_RECURRING"

O

 

Business purchases (Merchant selling to a business entity)

 

 

Property Example Requirement

1

(WOPA property) BuyerType
Calculated based on billingAddress.order.customer.fiscalNumber
 + countryCode.
Currently only set for Brazil,
if fiscalNumber length = 11, then INDIVIDUAL
if fiscalNumber length = 14, then BUSINESS
"BUSINESS" M

2

order.customer.contactDetails.emailAddress "johndoe@gmail.com" M

Customer.CompanyInformation.name
only required if fiscalNumber is deemed to be in Business format.
"Acme GmbH" O

 

Next Process flows