Adyen - Checkout implementation guide

Target Audience: Developers

Introduction

This document describes how you integrate Adyen in your web applications using the Payway API. The integration towards Payway is API-based which means you do not need a Payway session to use this integration, an access token is sufficient.

Before you start planning and writing code

Requirements and limitations

  • Feature enabled by Adeprimo
  • An access token for the user about to do the purchase with scope /external/adyen/r /external/adyen/w
  • HTTPS on the purchase page
  • Adyen payment periods.

Payment flow example

Sequence diagram

Step 1 Landing

Here you present your offer along with the available payment methods to the end-user. To better automate this process you can use the Product API to list the available payment methods.

Step 2 Configure widget and setup purchase

Here the user has opted into the purchase flow. Now you present the Adyen widget. But first, you need to populate the widget with the selected payment method from Step 1.

Fetch the payment method configuration needed to initiate the Adyen drop-in widget.

Request

1
2
3
4
curl --request GET \
  --url https://payway-api.stage.adeprimo.se/external/api/v1/adyen/payment_methods?period_id=<id selected in step 1>&product_code=adeprimo_digital&origin=https://purchase.example.com \
  --header 'accept: application/json' \
  --header 'authorization: Bearer <token-with-identity>' \

Parameters

Parameter Description Required Format Type
period_id Id of the payment period No (If not provided all Adyen payment methods will be returned) Size range ..24
Allowed values: "/^[a-f\d]{24}$/i"
String
product_code The product code for a package/campaign. Yes Size range ..100
Allowed values: "/^[a-f\d]{100}$/i"
String
origin URI where purchase is performed (E.g. https://purchase.example.org) Yes Size range: ..1024 Allowed values: uri regex that is too long to show here. Must be absolute String

Response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
HTTP 200
{
  "items": [
    {
      "details": [],
      "name": "Credit Card",
      "type": "scheme"
    }
  ]
}

Pass the result to the Adyen drop-in widget. Only pass the contents of "items", not the entire result. It is also important not to tamper with the result as the widget may not load properly if done so.

Adyen dropin widget example

An example implementation of the Adyen widget. This script is provided by Adyen and not Adeprimo. Hence any changes to it are not something Adeprimo can keep track of. Changes are done favorably in cooperation with Adeprimo to avoid any breaking changes. You can read more about the widget here.

Checkout the code sample for an example implementation of the Adyen Javascript library.

onSubmit event

This event is triggered when the user clicks the buy button in the Adyen drop-in widget.
The state data from the event needs to be passed to your backend along with some browser info and other required data. Your backend then performs a request to the /place_order endpoint.
The result contains information on whether the purchase was a success or if the user needs to perform additional actions. If additional actions are required you need to pass this information to the method, dropin.handleAction in the Adyen drop-in widget.

More on additional actions in Step 4.

If the purchase resulted in success or a pending payment you do not need to perform any additional actions.

onAdditionalDetails event

This event is triggered when dropin.handleAction has processed the action performed by the user. The state data from the event needs to be passed to your backend. Your backend then performs a request to /perform additional action. Same as for the onSubmit event.
The result contains information on whether the purchase was a success or if the user needs to perform additional actions. If additional actions are required you need to pass this information to the method dropin.handleAction in the Adyen drop-in widget.

In theory, your application needs to support n number of additional action requests.
Commonly the user only performs 1 additional action and then the purchase is completed. But there are cases where additional actions can occur more than once so you need to have support for it.

Step 3 Place order

The user presses the "buy" button in the widget. Here the onSubmit event is triggered. Post the state data you receive in the event to your server and call the /place_order endpoint.

Request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
curl --request POST \
  --url https://payway-api.stage.adeprimo.se/external/api/v1/adyen/place_order \
  --header 'authorization: Bearer <token-with-identity>' \
  --header 'content-type: application/json' \
  --data '{
  "payment_method": {
    "type": "scheme",
    "issuer": "265"
  },
  "product_code": "package_code",
  "period_id": "5e4beac909c04c404a46c730",
  "return_url": "https://returnurl.com",
  "traffic_source": null,
  "origin": "https://example.purchase.com",
  "browser_info": {
    "browser_ip": "127.0.0.1",
    "browser_language": "sv-FI",
    "browser_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
    "referer": "https://adeprimokuriren.se",
    "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "colorDepth": 24,
    "screenHeight": 723,
    "screenWidth": 1536,
    "timeZoneOffset": 0,
    "javaEnabled": true
  }
}'

Parameters

Parameter Description Required Format Type
payment_method Payment method received from state data in onSubmit event Yes Provided by Adyen widget Object
product_code The product code for a package/campaign. Yes Size range: 1..50 Allowed values: "/^[a-zA-Z-_0-9]+$/" String
period_id Id of the selected payment period Yes Size range ..24
Allowed values: "/^[a-f\d]{24}$/i"
String
return_url URI for payment provider redirects, e.q. 3D Secure 1 Yes Size range: ..1024 Allowed values: uri regex that is too long to show here. Must be absolute String
traffic_source The source of the purchase. E.g. facebook, web. Traffic sources need to be setup in PAP No Size range: ..100 String
origin URI where purchase is performed (E.g. https://purchase.example.org) String
browser_info Information about client browser Yes Object
browser_ip
Client ip-address Yes e.q. "127.0.0.1" String
browser_language
Client language Yes e.q. "sv-FI" or "sv-SE" String
browser_user_agent
Client user agent Yes e.q. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" String
referer
Origin URI of the request Yes e.q. "https://adeprimokuriren.se" String
accept_header
Client accept header Yes e.q. "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8" String
color_depth
Color depth of client browser Yes e.q. 24 Integer
screen_height
Screen height of client browser Yes e.q. 723 Integer
screen_width
Screen width of client browser Yes e.q. 1536 Integer
time_zone_offset
TimeZoneOffset of client browser Yes e.q. 0 Integer
java_enabled
Is java enabled on client browser Yes e.q. true/false Boolean

Here we can receive three types of answers. Depending on the status code received you will have to perform additional actions to complete the payment.

Purchase complete

1
2
3
4
5
6
7
8
9
HTTP 200 Purchase complete
{
  "item": {
    "receipt_id": "5e4becc109c04c404a46c744",
    "order_id": "ADEPRIMO-123",
    "message": "The payment was successfully authorised.",
    "status": "complete"
  }
}
If the status is "complete" then no additional actions need to be taken. The purchase has been completed and you can proceed to Step 5.

The "receipt_id" can be used to fetch the receipt for the recently made payment using the Me API.

Payment pending
1
2
3
4
5
6
7
HTTP 200 Payment pending
{
  "item": {    
    "message": "It's not possible to obtain the final status of the payment at this time.",
    "status": "pending"
  }
}

If the status is "pending" the user has completed the payment but the final result is not yet known. Payway will receive a callback when it is.

Payway either fails or completes the payment depending on the result.

For a successful result, the events associated with a completed purchase will be triggered. For instance order_closed.

In turn, all the events associated with a failed purchase will be triggered on an unsuccessful result. For instance payment_failure.

In the meanwhile, you can proceed to Step 5.

Action required
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
HTTP 200 Action required
{
  "item": {
    "action": {
      "paymentMethodType": "scheme",
      "token": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY...",
      "type": "threeDS2Fingerprint"
    },
    "session_reference": "session_reference",
    "message": "The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions.",
    "status": "action_required"
  }
}

If you receive the status "action_required" you need to perform additional action(s) to complete the purchase.

If you receive an "action" object, you need to pass it to the dropin.handleAction method found in the script. The result from dropin.handleAction should then be sent to your server to complete the additional action.

You will also receive a "session_reference" from Payway that you need to pass in Step 4.

Proceed to Step 4.

Step 4 Additional actions

Depending on the payment method and the customer bank settings you will need to perform additional actions to complete the purchase. If you did not receive the status "action_required" you can proceed to Step 5.

Otherwise, you need to perform a request to the /perform additional action endpoint.

Request

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl --request POST \
  --url https://payway-api.stage.adeprimo.se/external/api/v1/adyen/perform_additional_action \
  --header 'authorization: Bearer <token-with-identity>' \
  --header 'content-type: application/json' \
  --data '{
    "details": {
      "threeds2.fingerprint": "eyJ0aHJlZURTQ29tcEluZCI6IlkifQ=="
    },
    "session_reference": "5e4bfdf209c04c50ab62669d"
  }'

Parameters

Parameter Description Required Format Type
details Parameters received from Adyen either from dropin.handleAction or provider redirect Yes Provided by Adyen Object
session_reference Id of the payway purchase session Yes Size range ..24
Allowed values: "/^[a-f\d]{24}$/i"
String
origin URI where purchase is performed (E.g. https://purchase.example.org) Yes Size range: ..1024 Allowed values: uri regex that is too long to show here. Must be absolute String
Purchase complete

1
2
3
4
5
6
7
8
9
HTTP 200 Purchase complete
{
  "item": {
    "receipt_id": "5e4becc109c04c404a46c744",
    "order_id": "ADEPRIMO-123",
    "message": "The payment was successfully authorised.",
    "status": "complete"
  }
}
If the status is "complete" then no additional actions need to be taken. The purchase has been completed and you can proceed to Step 5.

The "receipt_id" can be used to fetch the receipt for the recently made payment using the Me API.

Payment pending
1
2
3
4
5
6
7
HTTP 200 Payment pending
{
  "item": {    
    "message": "It's not possible to obtain the final status of the payment at this time.",
    "status": "pending"
  }
}

If the status is "pending" the user has completed the payment but the final result is not yet known. Payway will receive a callback when it is.

Payway either fails or completes the payment depending on the result.

For a successful result, the events associated with a completed purchase will be triggered. For instance order_closed.

In turn, all the events associated with a failed purchase will be triggered on an unsuccessful result. For instance payment_failure.

In the meanwhile, you can proceed to Step 5.

Action required
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
HTTP 200 Action required
{
  "item": {
    "action": {
      "paymentMethodType": "scheme",
      "token": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY...",
      "type": "threeDS2Fingerprint"
    },
    "session_reference": "session_reference",
    "message": "The issuer requires further shopper interaction before the payment can be authenticated. Returned for 3D Secure 2 transactions.",
    "status": "action_required"
  }
}

If you receive the status "action_required" yet again you need to perform additional action(s) to complete the purchase until you receive the status "pending" or "complete".

The "action" object received needs to be passed to the dropin.handleAction method found in the script. The result from dropin.handleAction should then be sent to your server to complete the additional action by calling the /perform additional action endpoint.

You will also receive the "session_reference" again.

Proceed to Step 4 and perform it again.

Step 5 Present the result

Inform the user of the result

Handling redirect results

If you receive an action.type redirect during Step 3 or Step 4 , Drop-in redirects your shopper to another website using an HTTP GET or HTTP POST request. The shopper will be redirected back to your website using the same method.

Attention

The redirect method depends on your payment method configuration and the length of the data included in the request, so make sure that your integration can handle both HTTP GET and HTTP POST methods. See sample application for more info.

Depending on the HTTP method you need to either collect all the query parameters(HTTP GET) or all the data passed in the request body(HTTP POST) and pass them on as a POST request to /perform_additional_action.

3D Secure 1

As of writing this 2020-02-19, 3D Secure 1 is still around and needs to be supported. This means that in the case of 3DS1 verification the user will be redirected from your site to be verified.

To support these cases you will need to define the "return_url" in Step 3. Adyen will redirect the user to this endpoint when the purchase is completed.
To complete the purchase you will need to collect all the query parameters and send them in a POST request to /perform_additional_action.

In this case, you do not need to perform any additional actions. The status received in the subsequent response should only be "complete" or "pending".

3D Secure 2

When using Adyen Web Drop-in the 3D Secure 2 authentication will happen in the widget. This is supported out of the box by the Payway - Adyen integration.

You do need to prepare the UX/UI part of the verification of course. To test it out and have a better look use these test cards.

Notifications

See Adyen merchant portal configuration for more information.

URLs

Name URI
Payway API Stage Adyen base url https://payway-api.stage.adeprimo.se/external/api/v1/adyen
Payway API Prod Adyen base url https://backend.worldoftulo.com/external/api/v1/adyen
Adyen Customer Area Test https://ca-test.adyen.com/ca/ca/login.shtml
Adyen Customer Area Production https://ca-live.adyen.com/ca/ca/login.shtml

Payway API Endpoints

Name Description Relative url
Payment methods Get payment method configuration for initializing the Adyen dropin widget /payment_methods
Place order Place the initial order /place_order
Perform additional action Perform additional action required by Adyen /perform_additional_action

Sample application

An example application made in Ruby can soon be found here.

Errors

The error response is sent as application/JSON and will have an HTTP status code ranging between 400-500.

An error message will contain these properties in every response. Some error responses will add additional data for troubleshooting. Third-party errors from Adyen for example.

Error example

1
2
3
4
5
6
{
  "code": "error_code",
  "field": "field",
  "message": "error message",
  "correlation_id": "correlation_id only available for third party errors"
}

Testing

Before going live please be sure to complete the testing protocol.

Questions

Contact Adeprimo if you have questions or thoughts regarding the documentation and or integration. Or maybe you just want somebody to talk to.