<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adyen</title>
    <description>The latest articles on DEV Community by Adyen (@adyen).</description>
    <link>https://dev.to/adyen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2288%2F2bc231f0-951a-4eeb-8dfa-0ba1ce108adc.jpg</url>
      <title>DEV Community: Adyen</title>
      <link>https://dev.to/adyen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adyen"/>
    <language>en</language>
    <item>
      <title>Building a GlobalStream: Replication Challenges and Optimizations</title>
      <dc:creator>Ayodeji Ogundare</dc:creator>
      <pubDate>Fri, 10 Oct 2025 10:50:13 +0000</pubDate>
      <link>https://dev.to/adyen/building-a-globalstream-replication-challenges-and-optimizations-46jc</link>
      <guid>https://dev.to/adyen/building-a-globalstream-replication-challenges-and-optimizations-46jc</guid>
      <description>&lt;h4&gt;
  
  
  By Gaurav Singh &amp;amp; Luciano Sabença, Streaming Platform Team
&lt;/h4&gt;




&lt;p&gt;Global data streaming requires careful tradeoffs between performance, compliance, and reliability. At Adyen, replication is essential: data must remain close to producers to reduce latency and meet regulations, while also being centralized for analytics.&lt;/p&gt;

&lt;p&gt;In this blog, we share our experience optimizing MirrorMaker 2 for large-scale, cross-continent Kafka replication, the parameter tuning we applied, and the hidden behaviors in Kafka Connect that ultimately unlocked the required throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Replicate?
&lt;/h2&gt;

&lt;p&gt;There are many things you need to take into account when designing a data streaming platform for a company such as Adyen. One of the most important aspects of it is data location and replication. Due to performance, reliability, and compliance, keeping data close to producers is usually a good idea. After all, you don't want to wait in line at the cashier to confirm the payment for that fat burger you just bought on that nice beach in Australia while your payment was being sent to Europe. However, it's also a common practice to have all data in a centralized cluster(s) in centralized locations for analytical purposes. These two need a bridge, which is where mirroring comes in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcj3oho4kjf3sgwjy5rg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flcj3oho4kjf3sgwjy5rg.png" alt="An example replication flow diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mirror Maker
&lt;/h2&gt;

&lt;p&gt;When it comes to copying data between Kafka clusters, Mirror Maker is the default open source tool. MirrorMaker 2 is the current version, and it's built on top of Kafka Connect, a platform designed to make it easier to integrate Kafka with other tools such as databases and distributed file systems, and - why not? - another Kafka cluster. Setting up Mirror Maker is fairly straightforward, but tuning it to the performance Adyen requires isn't. Let's go over the journey into the depths of Kafka Connect and parameter tuning to find a solution!&lt;/p&gt;

&lt;h2&gt;
  
  
  Playing the Volume Game
&lt;/h2&gt;

&lt;p&gt;Kafka is a highly flexible tool and serves as the backbone for many different architectural patterns. It can be used for batch processing, real time processing, or any combination of these two extremes. With default parameters, Kafka producers and consumers are optimized for low-latency use cases: batch sizes are not large, and records are sent immediately to the server (i.e., linger.ms = 0). Given that our volume is on the order of several hundred thousand messages per second, any optimization has a huge impact on replication latency. In our case, the default settings were not good enough to keep the latency bounded within a few seconds; in fact, our replication latency was on the order of minutes. Since we are transferring this data across continents, we don't expect very low latency for replication, but such high latency indicates that we were at the maximum possible throughput for this configuration, so we needed to revisit those parameters.&lt;/p&gt;

&lt;p&gt;We made the following adjustments on the producer side of MirrorMaker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;batch.size&lt;/code&gt;&lt;/strong&gt;: Increased from the default 16384 to 409600. This leads to larger batches per request, and less requests to replicate the same number of messages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;linger.ms&lt;/code&gt;&lt;/strong&gt;: Increased from 0 to 200. This parameter sets how long the Kafka driver can wait before dispatching the messages. 0 means send immediately. Giving more time to the driver allows it to batch more messages in the same batch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;compression.type&lt;/code&gt;&lt;/strong&gt;: Changed from 'none' to 'zstd'. Activating compression means more messages per batch.&lt;br&gt;
These changes didn't yield the desired results. There was another bottleneck. We then turned our attention to the consumer parameters. After all, MirrorMaker is both a consumer from the source cluster and a producer to the destination. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We adjusted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;fetch.min.bytes&lt;/code&gt;&lt;/strong&gt;: Increased from 1 to 5000. So we wait a bit more to ensure that more data is available for consumption, thus decreasing the number of consumer requests and optimizing throughput. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;max.fetch.records&lt;/code&gt;&lt;/strong&gt;: Increased from 500 to 2000 with the objective of fetching more records per requests and sending more requests to the producer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal here was clear: have the consumers fetch as much data as possible at once and send it in very large batches to the destination cluster.  &lt;em&gt;The idea is to optimize network traffic and amortize large distance latencies when measured per unit of replicated byte.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Despite these efforts, the throughput remained stubbornly the same. Each time we restarted with new parameters, the record rate would spike briefly before settling back to its previous baseline, indicating that our changes were not having a lasting impact. This led us to believe there was a deeper, underlying issue we were missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Piece
&lt;/h2&gt;

&lt;p&gt;There was, however, a missing piece of the puzzle to make it work as we expect: how Kafka Connect changes are persisted and saved to the nodes. As we mentioned before, MM2 is built on top of Kafka Connect. Kafka Connect uses some internal Kafka topics to store and persist its state and configuration. This gives us three possible layers of configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kafka driver's parameters&lt;/li&gt;
&lt;li&gt;Mirrormaker configuration&lt;/li&gt;
&lt;li&gt;Internal Kafka Connect state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We needed to be sure that whenever any configuration was changed in any of these three places it would be reflected in the others. It soon became clear that this wasn't really the case: whilst our MM2 consumer was able to consume a quite decent amount of data, the producer wasn't really able to keep the throughput high and wasn't creating big enough batches for our use-case. &lt;/p&gt;

&lt;p&gt;After digging a bit into the internal configuration topics and on MM docs, we understood the root cause: configuration changes on the connectors are not updated while any instance of the connector is up and running. Instead, they are read from the internal mm configuration topics and applied to the connectors. This was our case: we are running MM2 in distributed mode, so we didn't stop all nodes and start them again. Although the behaviour makes sense, it prioritizes consistency when the application is running; it's not a very intuitive behavior and it almost led us to explore weird paths in our search for better throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Results: A Tale of Two Graphs
&lt;/h2&gt;

&lt;p&gt;The results were dramatic once we understood the necessity of a complete restart. As seen in the graph below, the number of records per request skyrocketed. We were also able to validate via logs and via the data in the topic that the parameters being used by the producers and consumers were the same as we originally intended.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uvyamjs3c6rikk656ft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uvyamjs3c6rikk656ft.png" alt="A graph showing the number of records per request" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a consequence of those parameters, the total number of requests sent by the producer dropped significantly and each request now was able to replicate more messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs15bqbonm9lheh2x5bxn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs15bqbonm9lheh2x5bxn.png" alt="Second graph showing the number of records per request" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This experience was a valuable lesson in the intricacies of managing a distributed system like Kafka Connect. Understanding the operational details of how configurations are managed was the key to unlocking the needed performance. &lt;em&gt;This journey highlights that sometimes the most significant gains come not from simply tweaking parameters, but from a deeper understanding of the tools themselves.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tech</category>
      <category>payments</category>
      <category>adyen</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Adyen API Diff Tool</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Tue, 19 Aug 2025 12:41:00 +0000</pubDate>
      <link>https://dev.to/adyen/adyen-api-diff-tool-3pjo</link>
      <guid>https://dev.to/adyen/adyen-api-diff-tool-3pjo</guid>
      <description>&lt;p&gt;APIs evolve quickly with new features, design changes, and deprecations, making it challenging for consumers to keep up. This impact can be significant: developers might miss valuable improvements, misunderstand the behavior of new features, delay the adoption of critical compliance updates. &lt;/p&gt;

&lt;p&gt;This is why we have put passion and effort in the Adyen API Diff Tool, a new tool designed to help developers and technical users easily track and compare changes between API versions.&lt;/p&gt;

&lt;p&gt;Whether you're maintaining an existing integration or building something new, staying on top of API changes is critical. Previously, this information was scattered across various sources like product announcements, documentation, release notes, and GitHub, resulting in a suboptimal user experience.&lt;/p&gt;

&lt;p&gt;This changes today with our new powerful &lt;a href="https://docs.adyen.com/api-explorer/api-diff-tool" rel="noopener noreferrer"&gt;API Diff Tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k1wsey8kg0sypcdev2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k1wsey8kg0sypcdev2e.png" alt=" " width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Our goal is simple: to make it easy to understand what’s changed in the Adyen APIs between any two versions.&lt;/p&gt;

&lt;p&gt;The Diff Tool includes built-in filters to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Compare API versions &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View changes by version, endpoint and HTTP method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Group changes by endpoint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spot quickly what’s new, changed, or removed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Focus on Breaking Changes only&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Labels, colors, and accordions provide a clean and effective way to visualize the changes. It is embedded directly in the API Explorer. From any specific change in the log, you can easily navigate to the relevant API reference or endpoint details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc9mbhofbeer61krmebo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc9mbhofbeer61krmebo.png" alt=" " width="800" height="753"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Benefits for Developers and other Users&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The API Diff Tool is designed to remove uncertainty when working with Adyen APIs. Whether you’re integrating for the first time or upgrading to a new version, it is a valuable tool to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Understand what changed**: compare any two API versions and see exactly what’s been added, removed, or modified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spot breaking changes early**: identify changes that could impact your integration, so you can plan ahead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Evolve faster and safer**: stay up-to-date with the latest API releases to integrate the new products and features available.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find what you need more quickly**: go to the API Explorer to find the API reference, the Diff Tool, a lot of examples and code snippets. Everything you need is in one place.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi8mbyacab5o5sbunbef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwi8mbyacab5o5sbunbef.png" alt=" " width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Acknowledgments and Credits&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This initiative was a true cross-team effort involving Technical Writers, Developer Relations, and API Champions. We've put significant thought and effort into delivering on our promise of a best-in-class Developer Experience.&lt;/p&gt;

&lt;p&gt;A special thank you goes to the open-source project &lt;a href="https://github.com/Tufin/oasdiff" rel="noopener noreferrer"&gt;&lt;strong&gt;OASDiff&lt;/strong&gt;&lt;/a&gt;, which powers the engine behind our Diff Tool. It enables detailed comparisons between OpenAPI specification files, detects breaking changes, and generates change diffs in multiple formats.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Next Steps: Collect Feedback and Iterate&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The API Diff Tool helps developers and integration partners manage API updates more efficiently. It simplifies upgrading to the latest API version, troubleshooting issues, and planning new integrations. By making API changes more transparent, this tool reduces friction and effort during the integration journey, ultimately enhancing the developer experience and accelerating new API adoption.&lt;/p&gt;

&lt;p&gt;In the next iteration we will be looking at adding support for webhooks and the option to subscribe to changes.&lt;/p&gt;

&lt;p&gt;The Adyen API Diff Tool is now available in our &lt;a href="https://docs.adyen.com/api-explorer/api-diff-tool" rel="noopener noreferrer"&gt;API Explorer&lt;/a&gt;! Try it out and share your feedback. We look forward to your input to continue improving.&lt;/p&gt;

</description>
      <category>api</category>
      <category>versioning</category>
    </item>
    <item>
      <title>A Developer’s Guide to HMAC Validation for Adyen Webhooks</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Mon, 16 Jun 2025 09:47:44 +0000</pubDate>
      <link>https://dev.to/adyen/a-developers-guide-to-hmac-validation-for-adyen-webhooks-4i96</link>
      <guid>https://dev.to/adyen/a-developers-guide-to-hmac-validation-for-adyen-webhooks-4i96</guid>
      <description>&lt;h1&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;When it comes to payments, security isn’t optional — it’s essential. If you’re integrating with Adyen, ensuring the incoming webhooks’ authenticity and integrity is very important. That’s where &lt;a href="https://www.okta.com/identity-101/hmac/" rel="noopener noreferrer"&gt;Hash-based Message Authentication Code&lt;/a&gt; (HMAC) plays a critical role in securing your Adyen integration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfrfwqccye08ez23fthp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfrfwqccye08ez23fthp.png" alt="Image description" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implementing, testing, and troubleshooting HMAC validation can be challenging. This guide explains how HMAC validation works, highlights the challenges, and provides tools and best practices for secure and reliable implementation.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;HMAC at Adyen&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;All Adyen webhooks use HMAC to ensure the integrity and authenticity of the payloads delivered to your integrations. The HMAC key should be &lt;a href="https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures/#enable-hmac-signatures" rel="noopener noreferrer"&gt;enabled&lt;/a&gt; when setting up a new webhook (either in the Customer Area Webhook page or using the &lt;a href="https://docs.adyen.com/api-explorer/Management/3/overview" rel="noopener noreferrer"&gt;Management API&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Adyen will use the HMAC key to sign the payload by creating an HMAC signature. You must validate the HMAC signature, delivered with the webhook, using the same HMAC key.&lt;/p&gt;

&lt;p&gt;Adyen webhooks fall into two main categories, each with its approach to HMAC implementation. Let’s explore the two scenarios.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;1. Payments Webhooks&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;For payments-related webhooks, the calculation of the signature involves using a &lt;a href="https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures/#verify-using-your-own-solution" rel="noopener noreferrer"&gt;subset of fields&lt;/a&gt;, and it’s embedded directly within the JSON payload under the &lt;code&gt;additionalData&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "live":"false",
   "notificationItems":[
      {
         "NotificationRequestItem":{
            "additionalData":{
               "hmacSignature":"+JWKfq4ynALK+FFzGgHnp1jSMQJMBJeb87dlph24sXw="
            },
          ...
         }
      }
   ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;2. Other Webhooks (Adyen for Platforms, Management)&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;For non-payment webhooks, the signature is calculated using the entire JSON payload. Instead of being included in the payload itself, the signature is provided in the HTTP Header &lt;code&gt;hmacSignature&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;content-length: 1614
content-type: application/json
hmacsignature: SMQZFOq3oIdugmf97u9TB+5256jjXgUX3MRjK+RlGNQ=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  &lt;strong&gt;Implementing HMAC Validation&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Developers have two options for implementing HMAC validation: creating their validation function or using the Adyen’s open-source libraries.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Custom Implementation&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;If you choose to implement your own HMAC validation, you’ll need to follow Adyen’s documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For payments webhooks, follow the &lt;a href="https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures/" rel="noopener noreferrer"&gt;Payment webhook HMAC validation guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For other webhooks, follow the &lt;a href="https://docs.adyen.com/api-explorer/Management/latest/overview" rel="noopener noreferrer"&gt;Platform webhook HMAC validation guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing a custom HMAC validation is not trivial — it requires handling the correct fields in the exact order and matching the encryption algorithm. Instead, use Adyen’s libraries to simplify the process, reducing both effort and risks.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Using Adyen Libraries (Recommended)&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Use the &lt;a href="https://github.com/Adyen" rel="noopener noreferrer"&gt;Adyen open-source libraries&lt;/a&gt;, which provide built-in functions for calculating and validating HMAC signatures. The libraries are thoroughly tested, regularly updated, and available in multiple programming languages (Node.js, PHP, Java, .NET, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String payload = "....";

// obtain signature
String hmacsignature = headers.get("hmacsignature");
if (hmacsignature == null || hmacsignature.isBlank()) {
   log.warn("HMAC Signature not found");
   throw new RuntimeException("HMAC Signature not found");
}

// perform HMAC validation 
if (!hmacValidator.validateHMAC(payload, hmacsignature, "MY_HMAC_KEY")) {
  throw new RuntimeException("Invalid HMAC signature");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example of Java snippet to validate the HMAC signature&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Known Issues and Challenges&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;HMAC validation errors are, unfortunately, common and challenging to troubleshoot. Several aspects contribute to this complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Propagation delay when updating the HMAC key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using the correct HMAC key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unexpected modification of the webhook payload&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;HMAC Key Update Propagation Delay&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;When users update (regenerate) the HMAC key associated with a webhook, there’s a delay (up to 10 minutes) before the new HMAC key is fully propagated and used by all webhook components. During this transition period, both the previous and new HMAC keys remain valid.&lt;/p&gt;

&lt;p&gt;This delay can lead to validation failures if the implementation isn’t prepared to handle the transition period, especially if you immediately discard the old key when generating a new one.&lt;/p&gt;

&lt;p&gt;The best practice here is to &lt;strong&gt;maintain both keys temporarily&lt;/strong&gt; during the transition window.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Using the Correct HMAC Key&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;One of the most common issues occurs when developers use the HMAC key from a different webhook configuration. With multiple webhooks in use, especially across development, testing, and production environments, it’s easy to mix up which key belongs to which webhook.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Key Check Value (KCV) Verification&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The Key Check Value (KCV) is a short hex value derived from the HMAC key that serves as a fingerprint to verify the key (without revealing it).&lt;/p&gt;

&lt;p&gt;The KCV is found on the Webhook Configuration page in the Adyen Customer Area (CA). When troubleshooting, always compare the KCV of the HMAC key you’re using with the one displayed in the CA to confirm you’re working with the correct key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm39xau0uzd6x47z2fi15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm39xau0uzd6x47z2fi15.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Webhook Configuration page showing the KCV&lt;/p&gt;

&lt;p&gt;You can validate the KCV by implementing the following steps:&lt;/p&gt;

&lt;p&gt;1. Calculate an 8-digit zero hash (“00000000”) using your HMAC key with the HMAC-SHA256 algorithm&lt;/p&gt;

&lt;p&gt;2. Take the last 3 bytes of the resulting hash and convert it to an uppercase hex string&lt;/p&gt;

&lt;p&gt;3. Compare this value with the KCV shown in the Customer Area&lt;/p&gt;

&lt;p&gt;Adyen’s libraries simplify this process by including &lt;a href="https://github.com/Adyen/adyen-node-api-library/tree/main/tools/hmac" rel="noopener noreferrer"&gt;scripts to calculate the KCV&lt;/a&gt;, making it easy to verify that you’re using the correct HMAC key.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Unexpected Modifications of the Webhook Payload&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;A common but often overlooked cause of HMAC validation failures is unintentional modification of the webhook payload.&lt;/p&gt;

&lt;p&gt;Adyen webhooks deliver information relevant to the customer’s integration (such as references, amounts, etc.) &lt;strong&gt;without trimming or encoding data&lt;/strong&gt;. However, application frameworks and third-party libraries might alter incoming requests in various ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Trimming whitespaces&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Converting line endings&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Normalizing JSON structures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decoding URL-encoded characters&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check if any infrastructure (web servers, API gateways, proxies) between Adyen and your application could be altering the payload of the incoming HTTP request.&lt;/p&gt;

&lt;p&gt;Before any framework processing, capture the raw webhook body and use the proper comparison (byte or string comparison rather than object matching). During your testing, &lt;strong&gt;it’s a good practice&lt;/strong&gt; to test payloads containing special characters and whitespaces to ensure proper handling.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;HMAC Validation Troubleshooting&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;When faced with HMAC validation failures, there are several approaches to troubleshoot and resolve the issue.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Test in Customer Area (CA)&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;The Adyen Customer Area provides a built-in feature to t&lt;a href="https://ca-test.adyen.com/ca/ca/config/webhooks.shtml" rel="noopener noreferrer"&gt;est your webhook configuration&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to Developers -&amp;gt; Webhooks -&amp;gt; Edit webhook&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on “Test Configuration”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose an “Event” type from the dropdown&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click “Test” to send the webhook to your endpoint&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify the HTTP response is successful by returning a 2xx response status code&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This page allows you to edit the webhook payload as needed (for example, changing a reference, amount, or other fields). The HMAC signature will be automatically recalculated and delivered with the new request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use Customer Area Testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Send webhooks from the Customer Area to verify the end-to-end flow: Adyen sends the webhook, your integration receives the event, and your implementation validates the HMAC signature. This method is ideal for confirming that the entire flow works correctly.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Test with Postman Collection&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Our &lt;a href="https://www.postman.com/adyendev" rel="noopener noreferrer"&gt;AdyenDev Postman&lt;/a&gt; space includes a Postman collection designed explicitly for webhook testing:&lt;/p&gt;

&lt;p&gt;1. Fork the Adyen Postman collection to your private workspace&lt;/p&gt;

&lt;p&gt;2. Define collection variables, including your HMAC key&lt;/p&gt;

&lt;p&gt;3. Update the webhook payload as needed&lt;/p&gt;

&lt;p&gt;4. Send the request to your application’s webhook endpoint&lt;/p&gt;

&lt;p&gt;The Adyen Webhooks Postman collection contains several sample payloads you can use or modify to simulate webhook events. It automatically calculates the HMAC signature when sending the request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use Postman testing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use Postman to test webhooks in isolation. This is ideal for validating your implementation without involving the Adyen backend and focusing on how your integration handles webhook events independently.&lt;/p&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;Test with Adyen Library Scripts&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Adyen libraries include built-in methods to calculate the HMAC signature using your HMAC key and JSON payload. Check out the code from GitHub or open the GitHub repository in Codespaces (browser-based development environment), and follow the instructions specific to the library&lt;/p&gt;

&lt;p&gt;For example, if you are using the &lt;a href="https://github.com/Adyen/adyen-node-api-library/" rel="noopener noreferrer"&gt;Node API library&lt;/a&gt; and need to troubleshoot an issue with the HMAC validation, you can calculate the HMAC signature in 2 simple steps.&lt;/p&gt;

&lt;p&gt;First go to the &lt;a href="https://github.com/Adyen/adyen-node-api-library/tree/main/tools/hmac" rel="noopener noreferrer"&gt;folder&lt;/a&gt; that includes the scripts, and install the necessary dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// go to dir and setup
cd tools/hmac
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calculate the HMAC signature, passing the JSON payload and the HMAC key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// run script passing the HMAC key and the JSON file with the payload
node calculateHmacPayments.js 11223344D785FBAE710E7F943F307971BB61B21281C98C9129B3D4018A57B2EB payload.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ &lt;strong&gt;Important&lt;/strong&gt;: When reusing a JSON payload, ensure it doesn’t get modified, formatted, or “prettified,” as this would alter the payload and result in a different signature.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Run in Codespaces&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;You can use effortlessly GitHub Codespaces to run these scripts directly from your browser:&lt;/p&gt;

&lt;p&gt;1. Open the GitHub repository for your Adyen library&lt;/p&gt;

&lt;p&gt;2. Start a Codespaces workspace&lt;/p&gt;

&lt;p&gt;3. In the terminal, navigate to the appropriate directory and run the scripts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@user ➜ cd /tools/hmac
@user ➜ npm install
up to date, audited 8 packages in 477ms

@user ➜ npm list @adyen/api-library
hmac-troubleshooting@1.0.0 /workspaces/adyen-node-api-library/tools/hmac
└── @adyen/api-library@25.0.0

@user ➜ node calculateHmacPayments.js 11223344D785FBAE710E7F943F307971BB61B21281C98C9129B3D4018A57B2EB payload.json

Calculating HMAC signature with payload from 'payload.json'
HMAC signature: qHNSvxCCix79xgBdWemxf0rcNMWoLrMK/4IgMnkOsWI=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use Library Built-in Scripts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use these scripts to troubleshoot HMAC validation failures in applications using the Adyen libraries: verify the expected HMAC signature using your HMAC key and payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;⚠️ Important: signatures not matching&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If your application calculates a different HMAC signature than these scripts, potential issues might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using an outdated version of the library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using the wrong HMAC key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Working with a modified payload (check for spaces, formatting, and special characters)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd451h3939xk7j3iw4j4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd451h3939xk7j3iw4j4a.png" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Key takeaways for successful HMAC implementation&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;This article explains HMAC validation, common challenges, and how to troubleshoot issues effectively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use Adyen’s open-source libraries to simplify HMAC validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manage HMAC key updates to avoid discarding old keys too early.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoid payload modifications to maintain signature integrity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leverage Adyen’s testing and troubleshooting tools.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow our guidelines and best practices to securely process Adyen webhooks and deliver a seamless payment experience to your shoppers 💚&lt;/p&gt;

</description>
      <category>webhooks</category>
      <category>hmac</category>
      <category>testing</category>
    </item>
    <item>
      <title>A Developer's Guide to the new iDEAL</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Tue, 10 Sep 2024 15:51:59 +0000</pubDate>
      <link>https://dev.to/adyen/a-developers-guide-to-the-new-ideal-2o0c</link>
      <guid>https://dev.to/adyen/a-developers-guide-to-the-new-ideal-2o0c</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.adyen.com/payment-methods/ideal/" rel="noopener noreferrer"&gt;iDEAL&lt;/a&gt;, a Dutch payment method that covers bank-to-bank transfers, was launched in 2005 and is the most popular payment method in the Netherlands today.&lt;/p&gt;

&lt;p&gt;Shoppers can pay quickly, safely, and easily with iDEAL through their bank's app, internet banking, or by scanning a QR code on their desktop. Whether it's a payment link after a purchase or a payment request from a friend, iDEAL comes in various forms, and the magenta iDEAL logo is synonymous with online payments for many people living in the Netherlands.&lt;/p&gt;

&lt;p&gt;As the payment ecosystem rapidly changes, with increasing demand for a smooth checkout experience, iDEAL is also upgrading its infrastructure, flows, and features.&lt;/p&gt;

&lt;p&gt;Read this blog to &lt;strong&gt;learn what is new in iDEAL 2.0&lt;/strong&gt; and what developers need to know.&lt;/p&gt;

&lt;p&gt;⚠️ This is a necessary compliance change: all existing payment integrations must be updated by April 1st, 2025.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features of iDEAL 2.0
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New infrastructure
&lt;/h3&gt;

&lt;p&gt;The new infrastructure introduces the iDEAL Hub and a centralized payment page where the users can select their bank. The goal is to facilitate adoption and streamline the onboarding process for banks, issuers, and payment providers. Shoppers will benefit from experiencing a consistent bank selection flow across different web shops, making the process familiar and trusted.&lt;/p&gt;

&lt;h3&gt;
  
  
  iDEAL profiles
&lt;/h3&gt;

&lt;p&gt;Consumers will be able to save their delivery details and preferred accounts, creating an iDEAL profile via their issuer bank. They can share this information with a webshop, completing the order and payment in one step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payment flows
&lt;/h3&gt;

&lt;p&gt;Profiles will help recognize returning users and make the payment faster by offering different options, such as a QR code, the iDEAL payment page, or a one-click payment checkout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling iDEAL 2.0
&lt;/h3&gt;

&lt;p&gt;The significant change in the iDEAL payment flow is the bank selection process. The list of available banks will no longer be part of the checkout form but will instead be available on the new iDEAL payment page. The checkout page must redirect shoppers to the iDEAL payment page, where iDEAL will handle both bank selection and payment execution.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;necessary compliance change&lt;/strong&gt; that requires all merchants to update the existing integrations.&lt;/p&gt;

&lt;p&gt;When adding iDEAL as a new payment method, for example when developing a new payment integration or if you configure a new merchant account, iDEAL 2.0 is enabled by default.&lt;/p&gt;

&lt;p&gt;For existing integrations on TEST we have configured the new iDEAL 2.0 payment method next to the existing one: update your payment integration and, when you are ready to test, activate iDEAL 2.0 in your Customer Area.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update your payment integration
&lt;/h2&gt;

&lt;p&gt;The changes required depend on the type of integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  API-only
&lt;/h3&gt;

&lt;p&gt;API-only integration is a method of integrating Adyen APIs where developers prefer to handle their checkout forms and user interfaces. This type of integration only requires one change: removing the list of banks from the Checkout page.&lt;/p&gt;

&lt;p&gt;Your payment integration must initiate an iDEAL payment using the Adyen Checkout &lt;code&gt;/payments&lt;/code&gt; API endpoint. Developers will no longer have to pass the issuer chosen by the shopper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "merchantAccount":"YOUR_MERCHANT_ACCOUNT",
  "reference":"YOUR_ORDER_NUMBER",
  "amount":{
    "currency":"EUR",
    "value":1000
  },
  "paymentMethod":{
    "type":"ideal"
  },
  "returnUrl":"https://your-company.com/checkout?shopperOrder=12xy.."
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;When using one our plugins to connect to an existing ecommerce, you only need to upgrade the relevant plugin:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adyen Magento v9.6.0+&lt;/li&gt;
&lt;li&gt;Salesforce Commerce Cloud v24.3.0+&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Web Drop-in and Components
&lt;/h3&gt;

&lt;p&gt;Payment integrations that embed the Web Drop-in or Components should upgrade the version of Adyen Web library to v5.65.0 or higher.&lt;/p&gt;

&lt;p&gt;The latest Adyen Web versions will no longer display the list of banks to the shopper, but only the redirect button to perform the payment on the iDEAL page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Good to know&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the bank selection picklist is no longer provided, you can safely remove any custom validation designed for the previous version of Adyen Components. This is especially important if you have hidden the default Component button and implemented a custom one.&lt;br&gt;
Additionally, note that iDEAL optional configurations from previous versions are no longer available and should be removed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq9d16j46wvr6rlcm7xw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq9d16j46wvr6rlcm7xw.png" alt="Image description" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out our sample applications on &lt;a href="https://github.com/adyen-examples" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; to see how to integrate the Web Drop-in and Components, and make a payment with iDEAL.&lt;/p&gt;
&lt;h3&gt;
  
  
  iOS and Android SDKs
&lt;/h3&gt;

&lt;p&gt;We have updated our iOS and Android mobile SDKs: make sure to use a version released after July 2024.&lt;/p&gt;

&lt;p&gt;For iOS, the additional configuration for iDEAL is no longer available and can be removed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Hosted Checkout
&lt;/h3&gt;

&lt;p&gt;No changes are required.&lt;/p&gt;
&lt;h2&gt;
  
  
  Activate iDEAL 2.0 in your Customer Area (Existing integrations)
&lt;/h2&gt;

&lt;p&gt;Log into the Customer Area, go to the "Payment methods" screen and select iDEAL with "iDealSim" acquirer. The next step is to click on "More actions" and choose the option "&lt;strong&gt;Deactivate&lt;/strong&gt;". Then select the other iDEAL payment method and activate it to route the iDEAL payments to the new infrastructure.&lt;/p&gt;

&lt;p&gt;From then on, all iDEAL payments will be performed using the new protocol.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnncaiceqjq84xm5meto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnncaiceqjq84xm5meto.png" alt="Image description" width="800" height="83"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Save the shopper's preferred bank
&lt;/h2&gt;

&lt;p&gt;The updated iDEAL allows storing the shopper's preferred bank, enabling direct redirection to the bank without requiring the selection on the iDEAL page.&lt;br&gt;
Note that this feature is available only with the &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/" rel="noopener noreferrer"&gt;Advanced Flow&lt;/a&gt; integration.&lt;/p&gt;
&lt;h3&gt;
  
  
  Save the shopper's Bank Identification Code (BIC)
&lt;/h3&gt;

&lt;p&gt;Adyen can send the bank information used by the shopper for the iDEAL payment through the payment &lt;a href="https://docs.adyen.com/api-explorer/Webhooks/latest/post/AUTHORISATION" rel="noopener noreferrer"&gt;Authorization Webhook&lt;/a&gt;. To enable this, navigate to the Customer Area and configure the Webhook by enabling the "Include Bank Account Details" option under "Additional Settings."&lt;/p&gt;

&lt;p&gt;After the iDEAL payment is completed, you will receive the Authorization Webhook. Extract the BIC number from the payload and store it for future use. You can then include it in the next iDEAL payments, indicating the BIC of the shopper's preferred bank.&lt;/p&gt;
&lt;h3&gt;
  
  
  Initiate the payment
&lt;/h3&gt;

&lt;p&gt;To initiate an iDEAL payment using the shopper's preferred bank, invoke the Checkout &lt;code&gt;/payments&lt;/code&gt; endpoint from your server-side application, as explained in the Advanced Flow integration. Ensure you set the &lt;code&gt;issuer&lt;/code&gt; field with the previously stored BIC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "merchantAccount":"YOUR_MERCHANT_ACCOUNT",
  "reference":"YOUR_ORDER_NUMBER",
  "amount":{
    "currency":"EUR",
    "value":1000
  },
  "paymentMethod":{
    "type":"ideal",
    "issuer":"BUNKNL2A"
  },
  "returnUrl":"https://your-company.com/checkout?shopperOrder=12xy.."
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the shopper decides to use a different bank, make a new iDEAL payment without the "issuer" attribute and let the iDEAL page manage the bank selection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The new iDEAL infrastructure provides an updated sandbox for testing. It's extremely important to validate your Adyen integration on our TEST environment to simulate the shopper's flow and test possible payment outcomes.&lt;/p&gt;

&lt;p&gt;When landing on the Bank Selection page, choose the "TESTNL2A" issuer to access the test page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjczaz66tm8pcxm31fb3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjczaz66tm8pcxm31fb3e.png" alt="Image description" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each scenario will trigger a different response that simulates the intended payment flow. Refer to the Adyen Docs &lt;a href="https://docs.adyen.com/payment-methods/ideal/api-only/#test-and-go-live" rel="noopener noreferrer"&gt;Test and Go Live&lt;/a&gt; page to find out what response to expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The new iDEAL 2.0 significantly enhances the shopper payment experience. It also streamlines the integration process for developers who want to offer iDEAL, thanks to introducing a centralized iDEAL page, a simplified bank selection process, and iDEAL shopper profiles. To align with these changes, developers are required to &lt;strong&gt;update their existing integrations by April 1st, 2025&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the Adyen TEST environment, we've made the migration to iDEAL 2.0 straightforward: simply update your existing integrations and test the new iDEAL flows.&lt;/p&gt;

&lt;p&gt;On the LIVE platform, the configuration already supports iDEAL 2.0. Once testing is complete, merchants can seamlessly transition to the new iDEAL without additional changes.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://docs.adyen.com/payment-methods/ideal/" rel="noopener noreferrer"&gt;iDEAL page&lt;/a&gt; and adopt the new iDEAL to offer shoppers the best experience with the most trusted payment method in the Netherlands.&lt;/p&gt;

</description>
      <category>payments</category>
      <category>testing</category>
    </item>
    <item>
      <title>Optimizing Webhook Integration: a new approach to accept events from the Adyen platform</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Thu, 02 May 2024 08:36:36 +0000</pubDate>
      <link>https://dev.to/adyen/optimizing-webhook-integration-a-new-approach-to-accept-events-from-the-adyen-platform-4hnh</link>
      <guid>https://dev.to/adyen/optimizing-webhook-integration-a-new-approach-to-accept-events-from-the-adyen-platform-4hnh</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.adyen.com/development-resources/webhooks/" rel="noopener noreferrer"&gt;Webhooks&lt;/a&gt; are crucial for getting updates and notifications from the Adyen platform. Those events include confirmation about, e.g., payment authorizations, modifications of existing payments, changes in the account data, or the availability of a new report. For any developers integrating with the Adyen platform, it’s essential to receive, acknowledge, and consume this information stream and ensure their ecommerce or payment is always up to date.&lt;/p&gt;

&lt;p&gt;Our teams also pay significant attention to keep improving the framework, ensuring reliability and performance meet the needs of our merchants and their use cases.&lt;/p&gt;

&lt;p&gt;As part of this simplification effort, &lt;strong&gt;we have introduced a different way&lt;/strong&gt; to acknowledge webhooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this article…&lt;/strong&gt; read how to accept webhooks delivered by Adyen, why we have changed the approach, the benefits, and the best practices we recommend for handling webhooks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Accepting webhooks
&lt;/h2&gt;

&lt;p&gt;The Adyen platform requires the webhook handlers to accept explicitly when a webhook is received so that Adyen can mark it as delivered.&lt;/p&gt;

&lt;p&gt;Webhooks that are not accepted end up in the &lt;a href="https://docs.adyen.com/development-resources/webhooks/troubleshoot/#retry-queue" rel="noopener noreferrer"&gt;Retry Queue&lt;/a&gt;: Adyen will progressively try to send those events again at predefined intervals until the applications can eventually consume them.&lt;/p&gt;

&lt;p&gt;The receiving applications &lt;strong&gt;must accept a webhook within 10 seconds&lt;/strong&gt;, implementing one of the two options available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accept with ‘[accepted]’ response body
&lt;/h3&gt;

&lt;p&gt;All integrations built with Adyen have been accepting webhooks by responding with a response body containing the string ‘[accepted]’. Applications failing to meet these specifications or taking longer than 10 seconds to do so would not successfully accept the webhook, triggering the retry process.&lt;/p&gt;

&lt;p&gt;This approach, implemented for years, has now been revised.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accept with any 2XX HTTP status code
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;new approach&lt;/strong&gt; simplifies the acknowledgment of webhooks.&lt;br&gt;
Whether you have built a custom integration or leveraged a middleware, all webhook handlers must respond only with a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#successful_responses" rel="noopener noreferrer"&gt;successful HTTP status code&lt;/a&gt; (2XX). Developers can choose any 2XX status code; providing a body with the HTTP response is unnecessary.&lt;/p&gt;

&lt;p&gt;Let’s see an example of how you can do this with NodeJS:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;// webhook handler implementation&lt;br&gt;
app.post("/api/webhooks/notifications", async (req, res) =&amp;gt; {&lt;/p&gt;

&lt;p&gt;// Notification Request JSON&lt;br&gt;
  const notificationRequestItems =  req.body.notificationItems&lt;br&gt;
  // fetch first (and only) NotificationRequestItem&lt;br&gt;
  const notification = notificationRequestItems[0].NotificationRequestItem&lt;/p&gt;

&lt;p&gt;// perform basic auth and HMAC validation&lt;br&gt;
  authorize();&lt;/p&gt;

&lt;p&gt;// consume event asynchronously (ie store in queue/db)&lt;br&gt;
   store(notification);&lt;/p&gt;

&lt;p&gt;// accept the event&lt;br&gt;
   res.status(202).send(); // Send a 202 response with an empty body&lt;br&gt;
});&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Benefits and remarks&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;There are multiple reasons behind the change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Align with industry standards
&lt;/h3&gt;

&lt;p&gt;As webhooks have become widely used in so many platforms and applications, there have been &lt;strong&gt;emerging industry standards&lt;/strong&gt; and best practices that we want to align with.&lt;/p&gt;

&lt;p&gt;Accepting webhooks by adopting the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202" rel="noopener noreferrer"&gt;HTTP status code 202&lt;/a&gt; ("Accepted"), for example, makes clear the semantics of the interaction: the consumer has received the event and will eventually process the content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better support for middleware
&lt;/h3&gt;

&lt;p&gt;We have seen the adoption of middleware for ingesting webhooks. Although ensuring the reliability and performance of the ingestion of events at scale, they might lack the flexibility of &lt;strong&gt;crafting custom response&lt;/strong&gt; bodies. &lt;/p&gt;

&lt;p&gt;Commercial services may also incur extra charges for delivering text within the response body, as this triggers an increased data transfer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove unnecessary ambiguity
&lt;/h3&gt;

&lt;p&gt;Exclusively relying on the content of the response body has presented scenarios where webhooks were successfully acknowledged even when responding with status codes in the 4XX and 5XX ranges, conventionally used to report an error.&lt;/p&gt;

&lt;p&gt;This has resulted in &lt;strong&gt;false negatives&lt;/strong&gt;, which not only affect the accuracy of performance metrics but also require additional effort to verify those cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  New webhooks
&lt;/h2&gt;

&lt;p&gt;Every newly created webhook on the Adyen platform will work with the &lt;strong&gt;2XX HTTP status code&lt;/strong&gt; option. Developers should understand how the new approach works and make sure that their implementation, either a bespoke webhook handler or the middleware, supports it by returning a successful HTTP response status code.&lt;/p&gt;

&lt;p&gt;If the 2XX HTTP status code option isn't compatible with your integration, reach out to the Adyen Support team, and we'll assist you in finding a suitable solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating existing webhooks
&lt;/h2&gt;

&lt;p&gt;All existing webhooks, however, are not automatically updated and keep functioning as before, relying on the &lt;strong&gt;'[accepted]' response body&lt;/strong&gt;. The migration is, however, straightforward and can be performed either in the Customer Area or programmatically using the Management API.&lt;/p&gt;

&lt;p&gt;Start planning the migration of your existing webhooks now and don't miss out on the advantages highlighted above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Webhook configuration in the CA
&lt;/h3&gt;

&lt;p&gt;In the Customer Area, go to the "Developers-&amp;gt;Webhooks" page and choose the webhook that is ready to be migrated. As you edit the webhook, in the "Server configuration" section, you will see the picklist "Accept webhook."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99rapyll317f6snb9s9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99rapyll317f6snb9s9s.png" alt="Webhook configuration screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The picklist provides two choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With '[accepted]'&lt;/li&gt;
&lt;li&gt;With HTTP 2XX&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Change the preferred approach to "With HTTP 2XX" and confirm the choice. Note that &lt;strong&gt;this change is permanent&lt;/strong&gt; and can't be reverted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtb5actur4qyzzvme97q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtb5actur4qyzzvme97q.png" alt="Confirmation popup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Update Webhook configuration using the Management API
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.adyen.com/api-explorer/Management" rel="noopener noreferrer"&gt;Adyen Management API&lt;/a&gt; allows to manage account and payment configuration programmatically. The API enables developers to perform and automate administrative tasks, configure settings and test webhooks.&lt;/p&gt;

&lt;p&gt;In order to update the webhook configuration and change the 'accept' mechanism you can perform a PATCH request setting the &lt;code&gt;acceptHttp200Confirmation&lt;/code&gt; property:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&lt;h1&gt;
  
  
  example on TEST environment
&lt;/h1&gt;

&lt;p&gt;PATCH &lt;a href="https://management-test.adyen.com/v3/merchants/%7BmerchantId%7D/webhooks/%7BwebhookId%7D" rel="noopener noreferrer"&gt;https://management-test.adyen.com/v3/merchants/{merchantId}/webhooks/{webhookId}&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
   "additionalSettings": {&lt;br&gt;
      "properties": {&lt;br&gt;
          "acceptHttp200Confirmation": "true"&lt;br&gt;
      }&lt;br&gt;
   }&lt;br&gt;
}&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Refactor webhook handlers&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Developers should also refactor the applications consuming the webhook events: provide a successful response, preferably with the HTTP status code 202, and ensure the response body is empty.&lt;/p&gt;

&lt;p&gt;When a middleware processes the webhooks, the configuration should also be updated to adopt the new approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices
&lt;/h2&gt;

&lt;p&gt;Consuming the webhooks delivered by the Adyen platform requires understanding and adopting best practices. Let's summarize them again:&lt;/p&gt;

&lt;h3&gt;
  
  
  Respond with 202 and empty body
&lt;/h3&gt;

&lt;p&gt;Acknowledge the webhook with an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202" rel="noopener noreferrer"&gt;HTTP status code 202&lt;/a&gt; ("Accepted") to indicate that the request has been successfully received, but the processing may not be complete.&lt;/p&gt;

&lt;p&gt;Any successful 2XX HTTP status codes can be used. However, the recommendation is to use 202.&lt;/p&gt;

&lt;p&gt;Returning an &lt;strong&gt;empty response body&lt;/strong&gt; is also a good practice, as it keeps the response lightweight and avoids unnecessary data transfer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Respond within 10 seconds
&lt;/h3&gt;

&lt;p&gt;The webhook handler must acknowledge the webhook within a 10-second window; failure to do so will prompt Adyen to retry sending the event later.&lt;/p&gt;

&lt;p&gt;There are a variety of reasons that can make the acceptance of the webhook longer than for 10 seconds. The affecting factors typically are the application's architecture, the complexity of the integration process, and the dependency on other systems or components.&lt;/p&gt;

&lt;p&gt;Consider therefore adopting an asynchronous approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store the event in a queue or database.&lt;/li&gt;
&lt;li&gt;Acknowledge the webhook with a response status code 202.&lt;/li&gt;
&lt;li&gt;Subsequently, process the event asynchronously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This strategy allows for more efficient handling of events, ensuring smoother integration and a predictable outcome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security (basic auth and HMAC)
&lt;/h3&gt;

&lt;p&gt;Implement the required &lt;a href="https://docs.adyen.com/development-resources/webhooks/best-practices/#security" rel="noopener noreferrer"&gt;security measures&lt;/a&gt; &lt;strong&gt;before acknowledging a webhook&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Enforce Basic Authentication (username and password) to ensure that only authorized parties can access the webhook endpoint.&lt;/p&gt;

&lt;p&gt;Integrate Hash-based Message Authentication Code (HMAC) validation to verify the integrity and authenticity of the webhook payload before consuming it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor event logs
&lt;/h3&gt;

&lt;p&gt;Use the &lt;a href="https://www.adyen.com/knowledge-hub/adyen-developer-dashboard" rel="noopener noreferrer"&gt;Developer Dashboard&lt;/a&gt; to monitor the health of your integration. The dashboard provides insights into the webhooks activity, aggregating valuable metrics like success rate and most frequent errors.&lt;/p&gt;

&lt;p&gt;When troubleshooting becomes necessary, dive into the Event Logs to inspect the events' status, payload, and response time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddyiu3fcfpz1b2ykune9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddyiu3fcfpz1b2ykune9.png" alt="Monitor webhook events"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The article outlines the new approach for accepting Adyen webhooks. We've compared the different methods, outlined the migration steps, and explained the rationale behind adopting any 2XX HTTP status code for webhook acknowledgment.&lt;/p&gt;

&lt;p&gt;Now it's time to plan your migration! Follow the recommended best practices, and don't hesitate to reach out if we can help you in any way with the transition.&lt;/p&gt;

</description>
      <category>webhooks</category>
      <category>developer</category>
    </item>
    <item>
      <title>A Guide to Integrating with Adyen Web for 3D Secure 2 Payments</title>
      <dc:creator>Sarah 🦄</dc:creator>
      <pubDate>Fri, 12 Jan 2024 14:36:30 +0000</pubDate>
      <link>https://dev.to/adyen/a-guide-to-integrating-with-adyen-web-for-3d-secure-2-payments-p3j</link>
      <guid>https://dev.to/adyen/a-guide-to-integrating-with-adyen-web-for-3d-secure-2-payments-p3j</guid>
      <description>&lt;p&gt;The goal of this guide is to provide the necessary context and examples to empower developers to handle 3D Secure 2 payments with the Adyen Web solution for the browser. This guide has a companion demo application with code examples for each flow which can be found in our &lt;a href="https://github.com/adyen-examples/adyen-node-online-payments/tree/main/3ds2-example" rel="noopener noreferrer"&gt;github examples&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is 3D Secure 2?
&lt;/h2&gt;

&lt;p&gt;3 Domain Secure (3DS) is a security measure for online payments. The 3 domains (acquirer, scheme, and issuer) interact with each other using a 3DS protocol where they exchange information, providing an authentication mechanism for the consumer during a transaction.&lt;/p&gt;

&lt;p&gt;3D Secure helps prevent fraud and is available for Card Not Present (CNP) transactions with all major card networks, and is mandatory in the EU, following the Revised Payment Services Directive (PSD2). For more in depth details about PSD2 and SCA you can refer to our &lt;a href="https://docs.adyen.com/online-payments/psd2-sca-compliance-and-implementation-guide/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When facilitating a card payment online we want to do all we can to ensure the shopper is who they say they are. This way we reduce fraudulent transactions and improve authorisation rates for real shoppers.&lt;/p&gt;

&lt;p&gt;There are two different ways customers can verify themselves using 3D Secure: frictionless and challenge. The frictionless flow is based on background information that doesn't require the customer to actively verify themselves. The challenge flow means the issuer has determined the transaction needs additional verification from the customer. For example; the shopper may have to enter a passcode they receive on their phone. The more information about the shopper we send in the payment request the higher the chances of a frictionless flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to support 3DS2 transactions with Adyen
&lt;/h2&gt;

&lt;p&gt;Our &lt;a href="https://github.com/adyen/adyen-web" rel="noopener noreferrer"&gt;Adyen Web SDK&lt;/a&gt; and &lt;a href="https://github.com/adyen-examples" rel="noopener noreferrer"&gt;server libraries&lt;/a&gt; support two options for 3DS2 payments: &lt;/p&gt;

&lt;h3&gt;
  
  
  Native
&lt;/h3&gt;

&lt;p&gt;The authentication experience occurs on your merchant page. Our SDK renders the necessary components and communicates directly with the ACS. The shopper never leaves your page. &lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect
&lt;/h3&gt;

&lt;p&gt;The authentication experience occurs on an Adyen page. Our SDK will redirect the shopper to an Adyen domain. The shopper is then redirected back to your merchant page once the authentication is complete. &lt;/p&gt;

&lt;p&gt;Both Native and Redirect flows can be either frictionless or challenged. Which option to choose depends on a multitude of factors and is out of scope for this guide. For more in depth information about each flow you can refer to our &lt;a href="https://docs.adyen.com/online-payments/3d-secure/#authentication-flows" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. This guide will show you how to integrate for both flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing Adyen Solutions
&lt;/h2&gt;

&lt;p&gt;When choosing a solution with Adyen you have a couple of choices to make; on the client side you can choose to integrate with our Drop-in or our Components. On the server side you can choose to integrate with our Sessions flow or our Advanced flow. This tutorial will demonstrate the Drop-in, you can follow along with our &lt;a href="https://github.com/adyen-examples/adyen-node-online-payments/tree/main/3ds2-example" rel="noopener noreferrer"&gt;Github example&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Drop-in vs. Components
&lt;/h3&gt;

&lt;p&gt;Drop-in is our pre-built UI for accepting payments. We recommend Drop-in as it renders a full list of available payment methods and does a lot of the heavy lifting for you. It also has 3D Secure 2 support built-in. &lt;/p&gt;

&lt;p&gt;Components are our customizable UI components which render individual payment methods. Choose Components if you prefer to compose your own UI. &lt;/p&gt;

&lt;p&gt;Both Drop-in and Components are available from our &lt;a href="https://github.com/Adyen/adyen-web" rel="noopener noreferrer"&gt;Adyen Web SDK&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Sessions flow vs. Advanced flow
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Sessions flow&lt;/strong&gt; consists of one API call that creates a payment session which is used by the Adyen Web SDK to facilitate the payment flow. The advantage is that with the Sessions flow you don’t have to do any extra work for 3DS2, everything is handled by the Drop-in/components. However, it’s important to note that the Sessions flow does not support 3DS2 redirect flow so if you wish to use redirect then you need to use the Advanced flow. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Advanced flow&lt;/strong&gt; consists of three API calls: /paymentMethods, /payments and /payments/details. You will need to configure and support each of these API calls in the advanced flow to facilitate the payment. Luckily you can use one of our Adyen &lt;a href="https://github.com/adyen#server-side" rel="noopener noreferrer"&gt;server libraries&lt;/a&gt; to make this a lot easier. &lt;/p&gt;

&lt;p&gt;When integrating with Adyen you can break it down to three core parts; the server, the client and the webhook. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server:&lt;/strong&gt; Handle the payment request(s) on your server using one of our API flows. &lt;br&gt;
&lt;strong&gt;Client:&lt;/strong&gt; Show the payment on your web page using our pre-built Drop-in or composing your own UI with our Components. &lt;br&gt;
&lt;strong&gt;Webhook:&lt;/strong&gt; Configure and receive webhook notifications with the outcome of each payment. Webhooks are out of scope for this guide. &lt;/p&gt;

&lt;p&gt;How 3DS2 is applied is dependent on your Dynamic 3DS rules. For more information on this please refer to our &lt;a href="https://docs.adyen.com/risk-management/dynamic-3d-secure/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Integrate with Sessions Flow
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This guide assumes you already have your Adyen API key and client key and are pointing to our TEST environment. If you haven’t you can find directions &lt;a href="https://docs.adyen.com/get-started-with-adyen/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s start with configuring the Sessions flow on our backend. The Sessions flow consists of one API call /sessions. &lt;/p&gt;
&lt;h3&gt;
  
  
  Install Adyen API library
&lt;/h3&gt;

&lt;p&gt;The first step is to install the Adyen API library, these examples will be in TypeScript so we’re going to use the &lt;a href="https://github.com/Adyen/adyen-node-api-library" rel="noopener noreferrer"&gt;Node.js library&lt;/a&gt;. These examples are built using version 15.1.0 of the api-library which utilizes the latest version of Checkout API (71). &lt;/p&gt;

&lt;p&gt;If you have npm installed, you install the library in your app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save @adyen/api-library
npm update @adyen/api-library

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure CheckoutAPI
&lt;/h3&gt;

&lt;p&gt;Now we have the library installed, let’s write our payment service. The first step is to initialize the Client object with your API key and environment, then we need to pass this client into the CheckoutAPI constructor to initialize our CheckoutAPI object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

import { Client, CheckoutAPI } from '@adyen/api-library';

// initialise the client object
 const client = new Client({
      apiKey: 'YOUR_API_KEY_HERE',
      environment: 'TEST',
 });

 // intialise the API object with the client object
 const paymentsAPI = new CheckoutAPI(client).PaymentsApi;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CheckoutAPI object exposes a few different API helpers, we want to use the PaymentsApi. Now we have initialized checkout, we can use it to call the sessions API. &lt;/p&gt;

&lt;h3&gt;
  
  
  Handle /sessions on the server
&lt;/h3&gt;

&lt;p&gt;First we create an asynchronous function to submit the sessions request. We build our request object with all of the fields we want to pass to our API. In the example below we include the fields we recommend to increase the chances of a frictionless flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

async postForSessions(data): Promise&amp;lt;CreateCheckoutSessionResponse&amp;gt; {
 const sessionsRequestData: CreateCheckoutSessionRequest = {
      amount: {
        currency: "EUR",
        value: 1000, 
      },
      countryCode: "NL",
      shopperName: {
        firstName: "FirstName",
        lastName: "LastName",
      },
      telephoneNumber: "0612345678",
      billingAddress: {
        houseNumberOrName: "1",
        street: "Shopper Billing Street",
        city: "Amsterdam",
        country: "NL",
        postalCode: "1234AB",
      },
      deliveryAddress: {
        houseNumberOrName: "1",
        street: "Shopper Delivery Street",
        city: "Amsterdam",
        country: "NL",
        postalCode: "1234AB",
      },
      shopperIP: "shopperIP",
      shopperEmail: "shopperEmail",
      channel: PaymentRequest.ChannelEnum.Web,
      reference: "YOUR_PAYMENT_REFERENCE",
      returnUrl: "https://your-company.com/checkout?shopperOrder=12xy..",
      merchantAccount: "YOUR_MERCHANT_ACCOUNT",
 };

 const sessionsResponse = await this.paymentsAPI.sessions(sessionsRequestData);
 return sessionsResponse;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above we pass the request data to the sessions function on the paymentsAPI object and return the awaited response. &lt;/p&gt;

&lt;p&gt;We have now set up our backend for the sessions flow. Let’s review what we did: &lt;br&gt;
✅ We installed the Adyen API library&lt;br&gt;
✅ We configured the Client object with our API key and environment &lt;br&gt;
✅ We instantiated the CheckoutAPI with our Client object and called the PaymentsAPI&lt;br&gt;
✅ We created a function to handle the /sessions API call&lt;/p&gt;

&lt;p&gt;Now let’s set up our frontend to send the request. &lt;/p&gt;
&lt;h3&gt;
  
  
  Install Adyen Web SDK
&lt;/h3&gt;

&lt;p&gt;In our frontend app we will use the &lt;a href="https://github.com/Adyen/adyen-web" rel="noopener noreferrer"&gt;Adyen Web SDK&lt;/a&gt; so let’s install it by running the command below. These examples are using version 5.55.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @adyen/adyen-web --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure our Drop-in looks as expected we need to import the Adyen web stylesheet in our app. This might look different depending on your set up. Here we will import it in our index.js file. You can override the styling rules to add your own styles. We also import the AdyenCheckout module so we can use it later to create our checkout instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.js

import AdyenCheckout from "@adyen/adyen-web";
import "@adyen/adyen-web/dist/adyen.css";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring the Web Drop-in
&lt;/h3&gt;

&lt;p&gt;Since we are using session flow our Drop-in requires the response from the sessions API call in its configuration. So let’s first make a call to our backend to receive the response from the /sessions endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//  ../frontend../dropin.js 

const sessionsRequest = {
// data for your request object, may include shopper details, the amount etc...  
}

const sessionsResponse = await postDoSessions(sessionsRequest);

// ../frontend../payments.js

export const postDoSessions = async (data) =&amp;gt; {
// send the sessions request to your backend  
const response = await fetch("/api/sessions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ data }),
  });
  return await response.json();

};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the sessions response we can now build our configuration object and create our checkout instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.js 

// create configuration object to pass into AdyenCheckout
const checkoutConfig = {
    locale: "en_US",
    environment: "test",
    clientKey: YOUR_ADYEN_CLIENT_KEY,
    session: sessionsResponse, // response from the /sessions call 
    onPaymentCompleted: onPaymentCompleted,
    onError: onError,
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our configuration object has two events which handle the payment:&lt;br&gt;
&lt;strong&gt;onPaymentCompleted&lt;/strong&gt; is triggered once the payment completes, here you can handle what should happen afterwards. &lt;br&gt;
&lt;strong&gt;onError&lt;/strong&gt; is triggered if an error is thrown. Use this event to gracefully handle errors for your shoppers. &lt;/p&gt;

&lt;p&gt;We create callback functions for each which will be executed when the events are invoked by the Drop-in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.js

  const onPaymentCompleted = (result, dropin) =&amp;gt; {
    // handle payment completed here
  };

  const onError = (error, dropin) =&amp;gt; {
    // handle error here
  };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a full list of all configuration options you can refer to our &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/?platform=Web&amp;amp;integration=Drop-in&amp;amp;version=5.55.1#drop-in-configuration" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we have our configuration object set up with our session data, let's instantiate the Drop-in,  pass the configuration to AdyenCheckout and mount the instance as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.js

const checkout = await AdyenCheckout(checkoutConfig);

// This will mount the checkout component to `&amp;lt;div id="dropin-container"&amp;gt;&amp;lt;/div&amp;gt;`
checkout.create("dropin").mount("#dropin-container");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component will be mounted to an element with an id of #dropin-container. For our last step let’s add a div element to our HTML with this id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.html

&amp;lt;div id="dropin-container"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we’ve set up our frontend to handle payments with Sessions flow and Drop-in. Let’s review what we just did: &lt;br&gt;
✅ We installed the Adyen Web SDK&lt;br&gt;
✅ We called our sessions API session data.&lt;br&gt;
✅ We created our configuration object passing the sessions response object and creating callback functions to handle the events. &lt;br&gt;
✅ We instantiated our checkout object with our config. &lt;br&gt;
✅ We created and mounted our Drop-in to our DOM. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6kw5bejpqnsfpdvb930.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz6kw5bejpqnsfpdvb930.jpg" alt="Diagram explaining sessions flow across client, server and Adyen domain"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Integrate with Advanced Flow
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This guide assumes you already have your Adyen API key and client key and are pointing to our TEST environment. If you haven’t you can find directions &lt;a href="https://docs.adyen.com/get-started-with-adyen/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;Let’s start with configuring the advanced flow on our backend. The advanced flow consists of three API calls &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/paymentMethods" rel="noopener noreferrer"&gt;/paymentMethods&lt;/a&gt;, &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/payments" rel="noopener noreferrer"&gt;/payments&lt;/a&gt; and &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/payments/details" rel="noopener noreferrer"&gt;/payments/details&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install Adyen API library
&lt;/h3&gt;

&lt;p&gt;The first step is to install the Adyen API library, these examples will be in TypeScript so we’re going to use the &lt;a href="https://github.com/Adyen/adyen-node-api-library" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; library. These examples are built using version 15.1.0 of the api-library which utilizes the latest version of Checkout API (71). &lt;/p&gt;

&lt;p&gt;If you have npm installed, you install the library in your app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save @adyen/api-library
npm update @adyen/api-library

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure CheckoutAPI
&lt;/h3&gt;

&lt;p&gt;Now we have the library installed, let’s write our payment service. The first step is to initialize the Client object with your API key and environment, then we need to pass this client into the CheckoutAPI constructor to initialize our CheckoutAPI object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

import { Client, CheckoutAPI } from '@adyen/api-library';

// initialise the client object
 const client = new Client({
   apiKey: 'YOUR_API_KEY_HERE',
   environment: 'TEST',
});

// intialise the API object with the client object
const paymentsAPI = new CheckoutAPI(client).PaymentsApi;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CheckoutAPI object exposes a few different API helpers, we want to use the PaymentsApi. &lt;/p&gt;

&lt;p&gt;The advanced flow consists of three API calls, let’s create functions to handle each of these requests. &lt;/p&gt;

&lt;h3&gt;
  
  
  Handle /paymentMethods on the server
&lt;/h3&gt;

&lt;p&gt;The initial &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/paymentMethods" rel="noopener noreferrer"&gt;/paymentMethods&lt;/a&gt; call is used to get a list of the available payment methods. We need to pass the response of this call to our Drop-in configuration. Which payment methods are returned depends on your merchant configuration. We build our request object with the fields we want to pass to the API. For this example we will just use the required field of merchantAccount. You can find the optional parameters &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/paymentMethods#request" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts 

async postForPaymentMethods(): Promise&amp;lt;PaymentMethodsResponse&amp;gt; {
    const postData = {
      merchantAccount: 'YOUR_MERCHANT_ACCOUNT',
    };

    const paymentMethodsResponse: PaymentMethodsResponse = await     this.paymentsAPI.paymentMethods(postData);

    return paymentMethodsResponse;
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handle /payments on the server
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/payments" rel="noopener noreferrer"&gt;/payments&lt;/a&gt; request sends the data related to the payment and the shopper. We want to call this when our shopper submits on the Drop-in. Our payments request may look different depending on whether we want to implement the native flow or the redirect flow. &lt;/p&gt;

&lt;h4&gt;
  
  
  Payment request for Native flow:
&lt;/h4&gt;

&lt;p&gt;If we want to implement the native flow then we need to set the threeDSRequestData object in the AuthenticationData object of the API request like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

const authenticationData: AuthenticationData = {
      threeDSRequestData: {
        nativeThreeDS: ThreeDSRequestData.NativeThreeDSEnum.Preferred, 
      },
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have set nativeThreeDS to be preferred, this will ensure we get the native flow. You can find the other optional parameters &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/payments#request-authenticationData-threeDSRequestData" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Now let’s build the rest of our request object and make the payments request. In the example below we include the fields we recommend to increase the chances of a frictionless flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

async postForPaymentsNative(data): Promise&amp;lt;PaymentResponse&amp;gt; {

    const paymentRequestData: PaymentRequest = {
      amount: {
        currency: "EUR",
        value: 1000,
      },
      authenticationData: {
        ...authenticationData, // pass our authenticationData object 
      },
      countryCode: "NL",
      shopperName: {
        firstName: "FirstName",
        lastName: "LastName",
      },
   telephoneNumber: "0612345678",
   billingAddress: {
     houseNumberOrName: "1",
     street: "Shopper Billing Street",
     city: "Amsterdam",
     country: "NL",
     postalCode: "1234AB",
   },
   deliveryAddress: {
      houseNumberOrName: "1",
      street: "Shopper Delivery Street",
      city: "Amsterdam",
      country: "NL",
      postalCode: "1234AB",
   },
      shopperIP: "ShopperIP",
      shopperEmail: "ShopperEmail",
      channel: PaymentRequest.ChannelEnum.Web,
      browserInfo: data.browserInfo, 
      origin: url, 
      paymentMethod: data.paymentMethod, 
   reference: "YOUR_PAYMENT_REFERENCE",
   returnUrl: "https://your-company.com/checkout?shopperOrder=12xy..",
   merchantAccount: "YOUR_MERCHANT_ACCOUNT",
    };

 const paymentResponse: PaymentResponse = await this.paymentsAPI.payments(paymentRequestData);

    return paymentResponse;
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above we pass the request data to the payments function on the paymentsAPI object and return the awaited response. &lt;/p&gt;

&lt;h4&gt;
  
  
  Payment request for Redirect
&lt;/h4&gt;

&lt;p&gt;Since redirect is the default in advanced flow we don’t need to pass any additional data to our authenticationData object in our payments request. &lt;/p&gt;

&lt;p&gt;We can just build our request object and make the payment request. In the example below we include the fields we recommend to increase the chances of a frictionless flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

async postForPaymentsRedirect(data): Promise&amp;lt;PaymentResponse&amp;gt; {

    const paymentRequestData: PaymentRequest = {
      amount: {
        currency: "EUR",
        value: 1000,
      },
     countryCode: "NL",
      shopperName: {
        firstName: "FirstName",
        lastName: "LastName",
      },
   telephoneNumber: "0612345678",
   billingAddress: {
     houseNumberOrName: "1",
     street: "Shopper Billing Street",
     city: "Amsterdam",
     country: "NL",
     postalCode: "1234AB",
   },
   deliveryAddress: {
      houseNumberOrName: "1",
      street: "Shopper Delivery Street",
      city: "Amsterdam",
      country: "NL",
      postalCode: "1234AB",
   },
      shopperIP: "ShopperIP",
      shopperEmail: "ShopperEmail",
      channel: PaymentRequest.ChannelEnum.Web,
      browserInfo: data.browserInfo, 
      origin: url, 
      paymentMethod: data.paymentMethod, 
   reference: "YOUR_PAYMENT_REFERENCE",
   returnUrl: "https://your-company.com/checkout?shopperOrder=12xy..",
   merchantAccount: "YOUR_MERCHANT_ACCOUNT",
    };

    const paymentResponse: PaymentResponse = await this.paymentsAPI.payments(paymentRequestData);

    return paymentResponse;
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Handling PaymentMethod and BrowserInfo
&lt;/h4&gt;

&lt;p&gt;In both native and redirect examples you may notice we set paymentMethod and browserInfo with the data object passed from the client. This data comes from the Drop-in state and is returned in the onSubmit event callback that we will define later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle /payments/details on the server
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.adyen.com/api-explorer/Checkout/71/post/payments/details" rel="noopener noreferrer"&gt;/payments/details&lt;/a&gt; request returns the details of the payment request we made. This response will include the result of the Authentication. What we pass to the details call is different depending on native or redirect flow, we will delve into this in the upcoming client section. For now we can create our request like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../backend/../payments.ts

 async postForPaymentDetails({ details }: { details: PaymentCompletionDetails }): Promise&amp;lt;PaymentDetailsResponse&amp;gt; {
    const paymentDetailsResponse: PaymentDetailsResponse = await this.paymentsAPI.paymentsDetails({ details });

    return paymentDetailsResponse;
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have now set up our backend for the advanced flow. Let’s review what we did: &lt;br&gt;
✅ We installed the Adyen API library&lt;br&gt;
✅ We configured the Client object with our API key and environment &lt;br&gt;
✅ We instantiated the CheckoutAPI with our Client object and called the PaymentsAPI&lt;br&gt;
✅ We created a function to handle the /paymentMethods API call&lt;br&gt;
✅ We created a function to handle the /payments API call&lt;br&gt;
✅ We created a function to handle the /payments/details API call&lt;/p&gt;

&lt;p&gt;Now let’s set up our frontend to send the request. &lt;/p&gt;
&lt;h3&gt;
  
  
  Install Adyen Web SDK
&lt;/h3&gt;

&lt;p&gt;In our frontend app we will use the Adyen Web SDK so let’s install it by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @adyen/adyen-web --save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure our Drop-in looks as expected we need to import the Adyen web stylesheet in our app. This might look different depending on your set up. Here we will import it in our index.js file. You can override the styling rules to add your own styles. We also import the AdyenCheckout module that we will use later to create our checkout instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend/../dropin.js

import AdyenCheckout from "@adyen/adyen-web";
import "@adyen/adyen-web/dist/adyen.css";

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring the Web Drop-in
&lt;/h3&gt;

&lt;p&gt;Since we are using advanced flow the first thing our client needs is the paymentMethods response from the /paymentMethods API so we can configure the drop-in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend/../dropin.js

 const paymentMethods = await getPaymentMethods();

// create configuration object to pass into AdyenCheckout
const checkoutConfig = {
      paymentMethodsResponse: paymentMethods,
      locale: "en_US",
      environment: "test",
      clientKey: CLIENT_KEY,
      onSubmit: onSubmit,
      onAdditionalDetails: onAdditionalDetails,
 };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our configuration object has two events which handle the payment. We create callback functions for each which will be executed when the events are invoked by the Drop-in.  &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;onSubmit&lt;/strong&gt; function is triggered when the shopper clicks the Pay button, here you can send the payment request and handle the response actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend/../dropin.js

const onSubmit = async (state, dropinComponent) =&amp;gt; {
  if (state.isValid) {
     const paymentResponse = await postDoPayment(state.data);
     // check result code and handle action here if required  
     if (paymentResponse.resultCode === "Authorised") {
        // no threeDS required
     } else if(paymentResponse.action) {
       dropinComponent.handleAction(paymentResponse.action);    
     }
  }
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code example above you can see we first check the state is valid to ensure there are no errors in the input and then pass the state.data to our payment request. This is the object that has the data for paymentMethod and browserInfo which we set in our API request. We await the payment response, the response will have a resultCode and depending on that resultCode it could also have an action object. An action is an additional step required which can be handled by the Drop-in handleAction method. Once we receive the response we check the resultCode and check if there is an action. Since we are building for 3DS2 we know we can expect an action of either &lt;strong&gt;redirect&lt;/strong&gt; or &lt;strong&gt;threeDS2&lt;/strong&gt; (for native). For more information on actions you can go &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/additional-use-cases/advanced-flow-integration/?platform=Web&amp;amp;integration=Drop-in&amp;amp;version=5.53.2#additional-front-end" rel="noopener noreferrer"&gt;refer to our documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;onAdditionalDetails&lt;/strong&gt; function is triggered if a payment method requires additional details. In our context this event will be invoked to handle the native 3DS2 result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend/../dropin.js

 const onAdditionalDetails = async (state, dropinComponent) =&amp;gt; {
      const paymentDetailsResponse = await postDoPaymentDetails(state.data);
      // handle result 
    };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When integrating with the 3DS2 native flow we use the onAdditionalDetails event callback to submit the /payments/details API call and get the final result. The onAddtionalDetails event is automatically triggered in native flow by the Drop-in once the shopper has completed the 3DS2 action. &lt;/p&gt;

&lt;p&gt;For a full list of all configuration options you can refer to our &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/additional-use-cases/advanced-flow-integration/?platform=Web&amp;amp;integration=Drop-in&amp;amp;version=5.53.2#configuring-drop-in" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. Now we have built our configuration object and handlers for the callbacks, let’s instantiate the drop-in, pass the configuration to AdyenCheckout and mount the instance as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend../dropin.js

const checkout = await AdyenCheckout(checkoutConfig);

// This will mount the checkout component to `&amp;lt;div id="dropin-container"&amp;gt;&amp;lt;/div&amp;gt;`
checkout.create("dropin").mount("#dropin-container");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component will be mounted to an element with an id of #dropin-container. For our last step let’s add a div element to our HTML with this id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// frontend/../dropin.html

&amp;lt;div id="dropin-container"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Handling the 3DS2 result
&lt;/h4&gt;

&lt;p&gt;We mentioned above that the &lt;em&gt;onAdditionalDetails&lt;/em&gt; callback is automatically triggered for native 3DS2. Here you will get the details result in the state.data object which is the first parameter of the callback event. Pass this data to the &lt;code&gt;/payments/details&lt;/code&gt; API to complete the 3DS2 transaction. &lt;/p&gt;

&lt;p&gt;If the integration is for 3DS2 redirect then we need to handle the redirect result differently. In a redirect flow when the shopper is redirected back to your merchant page the returnUrl will have the redirectResult appended, it might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://your-company.com/checkout?shopperOrder=12xy&amp;amp;redirectResult=X6XtfGC3%21Y...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we need to parse the url to get the redirectResult and then pass this to our &lt;code&gt;/payments/details&lt;/code&gt; call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ../frontend/../dropin.js

// example of how to parse redirect result from the url 
const parseRedirectResultToRequestData = (url) =&amp;gt; {
    const redirectResult = url.substring(url.indexOf("=") + 1, url.length);
  return {
    details: { redirectResult },
  };
};

const requestData = parseRedirectResultToRequestData(url);
const paymentDetailsResponse = await postDoPaymentDetails(requestData);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it, now we’ve set up our frontend to handle payments with advanced flow and Drop-in. Let’s review what we just did: &lt;br&gt;
✅ We installed the Adyen Web SDK&lt;br&gt;
✅ We called our paymentMethods API to get the paymentMethods data &lt;br&gt;
✅ We created our configuration object passing the paymentMethods data and creating callback functions to handle the events. &lt;br&gt;
✅ We instantiated our checkout object with our configuration. &lt;br&gt;
✅ We created and mounted our Adyen Drop-in in our DOM. &lt;br&gt;
✅ We handle the 3DS2 result in our onAdditionalDetails event callback in the native flow&lt;br&gt;
✅ We handle the 3DS2 result by parsing the redirectResult from the url in the redirect flow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdvq3fj8igk409fy3kp5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdvq3fj8igk409fy3kp5.jpg" alt="Diagram explaining advanced flow across client, server and Adyen domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile integrations
&lt;/h2&gt;

&lt;p&gt;This guide was intended for a browser flow of 3DS2 with Adyen Web. If you wish to integrate with 3DS2 for mobile we highly recommend using one of our dedicated mobile SDKs available for &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/?platform=Android&amp;amp;integration=Drop-in&amp;amp;version=5.5.0" rel="noopener noreferrer"&gt;Android&lt;/a&gt; or &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/?platform=iOS&amp;amp;integration=Drop-in&amp;amp;version=5.5.0" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;. If you still prefer to use a web integration then we strongly recommend using the redirect flow over native flow. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! In this blog we’ve covered: &lt;br&gt;
✅ What is 3D Secure 2&lt;br&gt;
✅ How Adyen supports 3DS2 transactions&lt;br&gt;
✅ A comparison between the different integration options&lt;br&gt;
✅ How to integrate using the Sessions flow&lt;br&gt;
✅ How to integrate using the Advanced flow&lt;br&gt;
✅ How to handle 3DS2 on the client-side using Adyen Drop-in &lt;/p&gt;

&lt;p&gt;We hope you find this technical blog helpful. Don’t forget to check out the &lt;a href="https://github.com/adyen-examples/adyen-node-online-payments/tree/main/3ds2-example" rel="noopener noreferrer"&gt;github repository&lt;/a&gt; which contains a fully working integration-example. It’s important to note that, while this guide promotes an ideal flow with our recommended best practices, all payment flows are uniquely complicated, so if this guide doesn’t exactly suit your needs, you can refer to our &lt;a href="https://docs.adyen.com/online-payments/" rel="noopener noreferrer"&gt;extensive documentation guides&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>payments</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Developer’s Guide: working with webhooks on your localhost</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Wed, 13 Dec 2023 15:57:46 +0000</pubDate>
      <link>https://dev.to/adyen/developers-guide-working-with-webhooks-on-your-localhost-3dgg</link>
      <guid>https://dev.to/adyen/developers-guide-working-with-webhooks-on-your-localhost-3dgg</guid>
      <description>&lt;p&gt;In this &lt;strong&gt;Developer Guide&lt;/strong&gt; you will learn how to consume and test webhooks in your local development environment. You will also understand the different advantages and disadvantages associated with the options we recommend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Webhooks are an essential feature of the Adyen platform. They deliver events like payment outcome, new chargebacks, availability of a report, updates on merchant onboarding, and so on, and therefore it is important to ensure they can be received, consumed and tested during the development of your specific Adyen integration.&lt;/p&gt;

&lt;p&gt;While inspecting the content of a webhook payload can be useful (for example by forwarding the webhook to tools like &lt;a href="https://webhook.site/" rel="noopener noreferrer"&gt;webhook.site&lt;/a&gt;), developers also require the capability to receive incoming webhooks directly in the application running on their laptop. It is a matter of more effective testing that verifies the correct processing on the incoming events and the associated workflow that follows.&lt;/p&gt;

&lt;p&gt;During the development of the application there are many changes to implement and many assumptions to confirm. The flexibility of working in the local environment is therefore crucial for both developer’s experience and productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s53e0y67i4fl5l5ej8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s53e0y67i4fl5l5ej8y.png" alt="Consuming webhook diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This developer guide explores the following options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adyen Postman Collection for webhooks&lt;/li&gt;
&lt;li&gt;Tunneling software&lt;/li&gt;
&lt;li&gt;Using a Cloud Development Environment (CDE)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Postman Collections
&lt;/h2&gt;

&lt;p&gt;Visit the AdyenDev Postman space and fork the &lt;a href="https://www.postman.com/beppecatanese/workspace/working-with-adyen/collection/8426282-f65935ea-8a87-4883-9f58-0eeac69e185a?action=share&amp;amp;creator=8426282" rel="noopener noreferrer"&gt;Adyen Webhooks&lt;/a&gt; collection. It includes several examples of the different types of webhooks.&lt;br&gt;
Each example provides the JSON payload with the event code and any other applicable field.&lt;br&gt;
The HMAC signature is calculated ‘on-the-fly’ and included in the HTTP request.&lt;/p&gt;

&lt;h2&gt;
  
  
  HowTo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fork the collection&lt;/li&gt;
&lt;li&gt;Configure the environment variables:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Webhook url (default &lt;code&gt;http://localhost:8080&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;HMAC key (same as configured in your application)&lt;/li&gt;
&lt;li&gt;Additional settings depending on your integration (Merchant Account for payments, Balance Platform Id for Platforms, etc..)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Send the requests to your application&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;p&gt;This is highly convenient in the initial development phase of the integration: developers want to quickly test the processing of the different JSON payloads that will be delivered by Adyen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt; ✅: easy to use with many different examples, flexible (can edit JSON payloads as needed), no need to expose a public endpoint&lt;br&gt;
&lt;strong&gt;Cons&lt;/strong&gt; ❌: not a real integration with Adyen backend&lt;/p&gt;

&lt;h2&gt;
  
  
  Tunneling Software
&lt;/h2&gt;

&lt;p&gt;Tunneling software tools such as ngrok and Microsoft Dev Tunnels can be used to expose your local environment to the internet. These tools essentially create a temporary connection between your local machine and a public endpoint, hosted by the company providing the tool.&lt;/p&gt;

&lt;p&gt;By establishing these tunnels you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow remote testing and collaboration&lt;/li&gt;
&lt;li&gt;Run demos using your local application&lt;/li&gt;
&lt;li&gt;Consume webhooks originated by a platform or third-party application, making webhook testing a lot simpler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below you can see how to test the webhook using ngrok, however the same approach applies when using a similar tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  HowTo with ngrok
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install ngrok&lt;/li&gt;
&lt;li&gt;Start ngrok &lt;code&gt;ngrok http 8080&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the ngrok generated URL for https&lt;/li&gt;
&lt;li&gt;Create/update Adyen webhook with the ngrok URL&lt;/li&gt;
&lt;li&gt;Ensure the HMAC key for the webhook is used by the application on your localhost&lt;/li&gt;
&lt;li&gt;Trigger a webhook: perform a payment or use Test Webhook function available in the Customer Area
&lt;strong&gt;Note&lt;/strong&gt;: when restarting ngrok a new URL is generated, therefore the Adyen webhook URL must also be updated.
When to use it
This option can be used throughout the development and testing of the integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt; ✅: receive webhooks sent by Adyen platform&lt;br&gt;
&lt;strong&gt;Cons&lt;/strong&gt; ❌: requires exposing localhost to the Internet&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Development Environment (CDE)
&lt;/h2&gt;

&lt;p&gt;A Cloud Development Environment (CDE) is an online development environment that allows developers to write, test, and deploy code from a web browser. It provides developers with the necessary tools to build and test software, without setting up and maintaining a local infrastructure (tech stack and all dependencies).&lt;br&gt;
As the development environment is hosted in a public cloud-based platform, it provides a convenient way to test webhooks.&lt;/p&gt;

&lt;p&gt;There are several CDEs (Gitpod, GitHub Codespaces, Codeanywhere, etc..). Choose your preferred tool, deploy your application source code and make it reachable by Adyen.&lt;/p&gt;

&lt;p&gt;Below you can see how to test the webhook using Gitpod (all Adyen sample applications can be &lt;a href="https://www.adyen.com/blog/-Run-any-of-our-samples-under-a-minute-using-GitPod" rel="noopener noreferrer"&gt;deployed on Gitpod&lt;/a&gt;), however a similar approach applies when using a different CDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  HowTo on Gitpod
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/adyen-examples/.github/blob/main/pages/gitpod-get-started.md" rel="noopener noreferrer"&gt;Configure&lt;/a&gt; the necessary settings (API key, merchant account, HMAC key) as Gitpod environment variables&lt;/li&gt;
&lt;li&gt;Deploy the application on Gitpod&lt;/li&gt;
&lt;li&gt;Copy the Gitpod generated URL (&lt;strong&gt;note&lt;/strong&gt;: not the Gitpod workspace URL but the URL of the web application running on Gitpod)&lt;/li&gt;
&lt;li&gt;Create a webhook using the generated Gitpod URL &lt;strong&gt;as well as&lt;/strong&gt; the path to access the webhook handler (ie &lt;code&gt;https://abcd1234.gitpod.io/api/webhooks/notifications&lt;/code&gt; by default)&lt;/li&gt;
&lt;li&gt;Generate the HMAC key for the webhook and copy it&lt;/li&gt;
&lt;li&gt;In the Gitpod terminal stop the application&lt;/li&gt;
&lt;li&gt;Set the HMAC KEY as env variable
&lt;code&gt;gp env ADYEN_HMAC_KEY=ASDEW##############&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update the environment variables for the terminal session
&lt;code&gt;eval $(gp env -e)&lt;/code&gt;
Restart the application in the terminal (or recreate the Gitpod workpace)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;p&gt;This approach might be suitable during testing and validation phases, later in the development lifecycle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt; ✅: receive webhooks sent by Adyen platform, source code can be tested and modified directly on Gitpod&lt;br&gt;
&lt;strong&gt;Cons&lt;/strong&gt; ❌: requires using cloud service, it must follow closely the “HowTo” steps (for example the Gitpod URL must be generated before configuring the webhook)&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Webhooks are a critical component of Adyen’s platform, and testing them effectively during development is essential.&lt;/p&gt;

&lt;p&gt;The ability to receive and process webhooks locally greatly enhances developer productivity. We’ve explored three options, each with its own advantages and limitations: Adyen Postman Collections for quick testing, tunneling software for ongoing development, and Gitpod for more comprehensive testing.&lt;/p&gt;

&lt;p&gt;Choose the approach that fits best with your needs, requirements and development methodology, and reach out to let us know what works for you and how we can help you further.&lt;/p&gt;

</description>
      <category>webhooks</category>
      <category>testing</category>
    </item>
    <item>
      <title>Simplify payment testing with the Adyen Test Cards browser extension</title>
      <dc:creator>Beppe Catanese</dc:creator>
      <pubDate>Mon, 27 Nov 2023 13:50:46 +0000</pubDate>
      <link>https://dev.to/adyen/simplify-payment-testing-with-the-adyen-test-cards-browser-extension-1jnf</link>
      <guid>https://dev.to/adyen/simplify-payment-testing-with-the-adyen-test-cards-browser-extension-1jnf</guid>
      <description>&lt;p&gt;Testing payment flows is a challenging and time-consuming process, involving multiple steps, different payment methods, and manually entering data such as card details. &lt;/p&gt;

&lt;p&gt;We’ve built the &lt;a href="https://chrome.google.com/webstore/detail/adyen-test-cards/icllkfleeahmemjgoibajcmeoehkeoag" rel="noopener noreferrer"&gt;Adyen Test Card Chrome extension&lt;/a&gt; to solve this challenge, designed to simplify the testing process. By adding the extension directly to your browser, you can copy the card details to the clipboard or prefill the Adyen web Drop-in with a single click.&lt;/p&gt;

&lt;p&gt;In this article, you’ll discover the benefits of the Adyen Test Cards extension, how we built it, and what it means in terms of security.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbr2qoez0g19wy2ile1mx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbr2qoez0g19wy2ile1mx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet the Adyen Test Card extension
&lt;/h2&gt;

&lt;p&gt;Given the high number of returning visitors to the Adyen Test Cards page, we saw an opportunity to assist developers by streamlining the testing process. This is why we built the extension: to simplify the testing of payment flows for developers.&lt;/p&gt;

&lt;p&gt;Designed to facilitate Adyen Checkout integration testing, the Adyen Test Card extension reduces the time and effort spent on payment flow testing. It brings the test card numbers you need directly into your browser and simplifies the testing process for developers. It removes the burden of going back and forth between different pages to collect the card data you need to test. &lt;/p&gt;

&lt;p&gt;To make the design as simple as possible, we used &lt;a href="https://developer.chrome.com/docs/extensions/reference/sidePanel/" rel="noopener noreferrer"&gt;chrome.sidePanel&lt;/a&gt;, a pre-built side panel that doesn't overlap with the tab's content and that can be easily resized or closed. The extension builds its UI and logic within the side panel, creating features that deliver user experiences that nicely blend with the &lt;a href="https://docs.adyen.com/online-payments/build-your-integration/" rel="noopener noreferrer"&gt;Adyen Drop-in&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make testing easy
&lt;/h2&gt;

&lt;p&gt;There are multiple features that contribute to enhancing the testing experience for developers. The most significant ones are:&lt;/p&gt;

&lt;h3&gt;
  
  
  One-click prefill
&lt;/h3&gt;

&lt;p&gt;Testing checkout integrations previously meant spending time searching for the right card, copying (from the Adyen Test Cards page or your local file) and pasting it in the right field, then repeating the same process for the expiry date and CVC data.&lt;/p&gt;

&lt;p&gt;Now, the one-click prefill feature of the Adyen Web Drop-in does it for you. All you need to do is find the card information you need, select, and paste it in the right field.&lt;/p&gt;

&lt;p&gt;There is also a copy-to-clipboard feature in case the card number needs to be used with applications that don't use the Adyen Web Drop-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkwndfh69iyp2043cfds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkwndfh69iyp2043cfds.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pin your favorites
&lt;/h3&gt;

&lt;p&gt;You can use the ‘’Add to Favorites’’ option to speed up the testing process further. This feature makes it possible to pin frequently used cards to the top of the extension panel for quick, convenient access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different payment methods
&lt;/h3&gt;

&lt;p&gt;Next to the different credit and debit cards, the extension also supports gift cards and IBANs. You can also &lt;a href="https://github.com/adyen-examples/adyen-testcards-extension/issues" rel="noopener noreferrer"&gt;submit a request&lt;/a&gt; to add other payment methods or card numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Installing the extension is easy and can be done in the Chrome Web Store by searching for the Adyen Test Cards extension. All you need to do is click the “Add to Chrome” button. &lt;/p&gt;

&lt;p&gt;Watch the video on our &lt;a href="https://www.youtube.com/watch?v=INDxpfjnAnE" rel="noopener noreferrer"&gt;AdyenDev YouTube&lt;/a&gt; channel for a detailed guide on installing and using the extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;The extension is designed with security as a key consideration, promoting best practices in payment security by discouraging using real cards for testing.&lt;/p&gt;

&lt;p&gt;The Adyen Test Cards extension only copies (using Javascript) the selected card details into the checkout form. No other data or fields are read or changed. The &lt;a href="https://github.com/adyen-examples/adyen-testcards-extension" rel="noopener noreferrer"&gt;source code&lt;/a&gt; is Open-Source, and the extension has no telemetry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build and Testing
&lt;/h2&gt;

&lt;p&gt;Developing the Chrome extension is an easy process. You first need to create a manifest file in a JSON format that defines the extension's metadata, permissions, and assets. &lt;/p&gt;

&lt;p&gt;In the manifest file, you can find the permissions required by the extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"sidePanel": Gives you access to the Chrome side-panel component.&lt;/li&gt;
&lt;li&gt;"scripting": Allows you to execute the script to modify the page's content, specifically by populating the card details into their corresponding fields.&lt;/li&gt;
&lt;li&gt;"activeTab": Permits you to only interact with the active tab.&lt;/li&gt;
&lt;li&gt;"storage": Lets you save the list of favorite cards in the local storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, you need to develop the source code that contains several elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript and HTML code: Implements the functional behavior and rendering of the user interface.&lt;/li&gt;
&lt;li&gt;Content script: Javascript code that manages the extension's interaction with the tab's content.&lt;/li&gt;
&lt;li&gt;Service worker: Background script that manages the extension's state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Chrome extension is loaded directly from the source code during the development, leveraging the Chrome Developer mode and making code modifications immediately visible. This, combined with using Chrome DevTools, makes debugging and troubleshooting a lot easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw112dbk2o0kxgagrferm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw112dbk2o0kxgagrferm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking testing to the next level
&lt;/h2&gt;

&lt;p&gt;The Adyen Test Cards Chrome extension helps developers perform more convenient, secure, and effective testing. By quickly accessing a list of test card data without manually entering the information, you can speed up the testing process and spend more time developing the integration without wasting time and energy on repetitive tasks.&lt;/p&gt;

&lt;p&gt;Adyen Test Cards Data mimics real transactions, allowing you to test different scenarios and outcomes. By eliminating the manual entry of the payment method details, the extension reduces the possibility of error during testing, resulting in more robust integrations.&lt;/p&gt;

&lt;p&gt;We’re proud to support developers during their integration journey with the Adyen platform. Providing effective tools removes friction, boosts productivity, and ultimately contributes to a better and more robust integration.&lt;/p&gt;

&lt;p&gt;Get started by installing the Adyen Test Card extension from the &lt;a href="https://chrome.google.com/webstore/detail/adyen-test-cards/icllkfleeahmemjgoibajcmeoehkeoag" rel="noopener noreferrer"&gt;Chrome Store&lt;/a&gt; or downloading it from the source code on &lt;a href="https://github.com/adyen-examples/adyen-testcards-extension" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Give us your feedback, and let us know what you think should be included in the next releases.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>payments</category>
      <category>chrome</category>
      <category>extensions</category>
    </item>
    <item>
      <title>Sweeps on the Adyen Balance Platform for Developers</title>
      <dc:creator>Kwok He Chu</dc:creator>
      <pubDate>Mon, 20 Nov 2023 15:18:06 +0000</pubDate>
      <link>https://dev.to/adyen/sweeps-on-the-adyen-balance-platform-for-developers-672</link>
      <guid>https://dev.to/adyen/sweeps-on-the-adyen-balance-platform-for-developers-672</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; In this blog post, we show you how you can configure sweeps to automate payouts to your user's verified bank accounts. We’ll explain the different types of sweeps, outline the scenarios they are designed for, and explain the process of setting up sweeps through either the Customer Area or using APIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.adyen.com/marketplaces-and-platforms/%20https://docs.adyen.com/marketplaces-and-platforms/"&gt;Adyen for Platforms&lt;/a&gt; offers a comprehensive solution tailored for marketplaces that aim to deliver a flexible, robust and fully-featured platform to support their merchants and end users on a large scale. The core of every successful platform is the unique relationship built over time between the platform and its customers. Merchants process a vast number of complex transactions everyday, with different attributes and configurations, like currency, payment methods, split amounts and fees. They also need easy access to their funds, making fast and reliable payouts an indispensable tool of the platform.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll answer the following questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What are sweeps?&lt;/li&gt;
&lt;li&gt;What types of sweeps exist and their use cases.&lt;/li&gt;
&lt;li&gt;How to configure sweeps.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What are sweeps?
&lt;/h2&gt;

&lt;p&gt;Let’s start with an example. Jan runs a very successful marketplace that allows users to buy and sell their cars in Amsterdam. As their user base grows, Jan is having trouble with making sure his users are paid out consistently at a set interval. This has proven quite troublesome as more and more users join their marketplace. Jan is looking for some kind of automation. This is where sweeps come into play, an Adyen feature that allows him full control of his payout functionality. Sweeps pull in or push out funds from a balance account based on a predefined schedule, amount, currency, and a source or a destination.&lt;/p&gt;

&lt;p&gt;Before we delve into the specifics, let’s clarify two key terms: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Account holder:&lt;/strong&gt; This refers to the user entity within the balance platform. Depending on your account structure, the account holder can either be your company, or your customers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Balance account:&lt;/strong&gt; This is the account where funds are held for an account holder. All financial activity happens through balance accounts. Each account holder can have one or more balance accounts for accounting flexibility, but in most use cases, a single balance account is sufficient.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KSB4fdAy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzyfljyvh3l8sc5gro1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KSB4fdAy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tzyfljyvh3l8sc5gro1g.png" alt="Account holder and balance account structure image" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An account holder can be one of the following legal entities: &lt;em&gt;Individual&lt;/em&gt;, &lt;em&gt;Business&lt;/em&gt;, &lt;em&gt;Nonprofit&lt;/em&gt;, &lt;em&gt;Partnership&lt;/em&gt;, or &lt;em&gt;Public company&lt;/em&gt;. To create an account holder, send a request to the &lt;em&gt;/createAccountHolder&lt;/em&gt; endpoint. Refer to this &lt;a href="https://docs.adyen.com/marketplaces-and-platforms/classic/account-holders-and-accounts/?tab=create-partnership-request_4#create-an-account-holder"&gt;documentation page&lt;/a&gt; to understand the different request parameters for each legal entity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.adyen.com/marketplaces-and-platforms/classic/account-holders-and-accounts/"&gt;Account holders&lt;/a&gt; rely on the platforms for the benefit of their business but also for features like reliability and ease of access to their funds. The skeleton of reliability, trust and ease are equal parts of a massive pillar in this business model. The core of this trust relies on the payout functionality being spot on and easy for both the account holders and the platforms to configure and customize based on their needs. &lt;/p&gt;

&lt;h2&gt;
  
  
  What types of sweeps exist?
&lt;/h2&gt;

&lt;p&gt;A sweep automatically pushes out or pulls in funds from a balance account based on a predefined schedule, amount, and source or destination. There are two types of sweeps that exist as part of the Adyen Balance Platform. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The push sweep &lt;/li&gt;
&lt;li&gt;The pull sweep&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The push sweep
&lt;/h3&gt;

&lt;p&gt;The push sweep is the type of sweep used for configuring payouts. Platforms use this type of sweep to send a payout to the account holders based on a configurable schedule and other additional parameters such as the currency. &lt;/p&gt;

&lt;p&gt;The push sweep is configured for the balance account of the account holder. This means that an account holder with multiple balance accounts can define sweeps with different configurations, based on the preferences of the business case.&lt;/p&gt;

&lt;h3&gt;
  
  
  The pull sweep
&lt;/h3&gt;

&lt;p&gt;The pull sweep is the type of sweep used for the auto-funding functionality on the balance platform for account holders. Platforms can use this type of sweep to pull funds into a designated balance account when a certain threshold is reached. &lt;/p&gt;

&lt;p&gt;Auto-funding use cases are those as old as time, where an account holder needs funds to process refunds but is below a threshold to process them successfully. At this point, the autofunding functionality configured via a pull sweep comes to the rescue by pulling in funds for operational ease. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to configure sweeps
&lt;/h2&gt;

&lt;p&gt;You can configure sweeps for balance accounts through two primary methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customer Area &lt;/li&gt;
&lt;li&gt;API functionality &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Customer Area
&lt;/h3&gt;

&lt;p&gt;You can directly configure sweeps for balance accounts via the Customer Area by performing the following steps:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into the Customer Area using your credentials. &lt;/li&gt;
&lt;li&gt;Navigate to the account holder. &lt;/li&gt;
&lt;li&gt;Navigate to the balance account you want to configure the sweep for. &lt;/li&gt;
&lt;li&gt;On the balance account page, use the button as shown below to add a sweep configuration for the balance account. 
Choose the type of sweep you would like to configure. For the purpose of this example, we will be proceeding with the push sweeps for payouts. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qm-ahtl9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ac7l78009hgims22fei.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qm-ahtl9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ac7l78009hgims22fei.jpg" alt="Balance account details image" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once the type of sweep has been selected, you will proceed to a page with an extensive range of customization options that allow you to tailor the structure of your sweep according to your preferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---2s0iYzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03xlpuu8yyah8pc3zq9m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---2s0iYzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03xlpuu8yyah8pc3zq9m.jpg" alt="Select your sweep image" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally confirm the configuration by clicking next and viewing the summary of the sweep you are ready to create. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UrlFgW5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjaa8kaq91nh8qxr74po.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UrlFgW5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjaa8kaq91nh8qxr74po.jpg" alt="Add sweep configuration image" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  API functionality
&lt;/h3&gt;

&lt;p&gt;For developers, it is possible to use the Adyen Platform &lt;a href="https://docs.adyen.com/api-explorer/balanceplatform/latest/overview"&gt;Configuration&lt;/a&gt; APIs for automating the sweep configurations for account holders. &lt;/p&gt;

&lt;p&gt;You can create a sweep by specifying its type and send a POST request to the &lt;a href="https://docs.adyen.com/api-explorer/balanceplatform/latest/post/balanceAccounts/_balanceAccountId_/sweeps"&gt;/balanceAccounts/{balanceAccountId}/sweeps&lt;/a&gt; endpoint. You can configure the request parameters in the body of the API call as shown below. For a more detailed overview on what each of these parameters do, read our API documentation &lt;a href="https://docs.adyen.com/api-explorer/balanceplatform/latest/post/balanceAccounts/_balanceAccountId_/sweeps"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Create a push sweep using a POST request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"counterparty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"balanceAccountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BA3233T22337JX5JVZFTEPC91B"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;destination&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;funds&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sweep&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cronExpression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"30 9 * * 3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;cron&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expression&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;schedule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sweep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;validated&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cron"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;schedule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sweep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;evaluated&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"push"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sweep&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Internal funds transfer every Wednesday at 0930"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful request returns the newly created push sweep.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SWPC4233T22337JX5JVZGSP39S4M7K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cron"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cronExpression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"30 9 * * 3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"targetAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"triggerAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"push"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"counterparty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"balanceAccountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BA3233T22337JX5JVZFTEPC91B"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Internal funds transfer every Wednesday at 0930"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adyen will also asynchronously send the "&lt;em&gt;balancePlatform.balanceAccountSweep.created&lt;/em&gt;" webhook with the sweep response. You can find an example of the webhook payload below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"balancePlatform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_BALANCE_PLATFORM"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BA3233T22337JX5JVZGSPD9B9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sweep"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SWPC4233T22337JX5JVZGSP39S4M7K"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"weekly"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"targetAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"triggerAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"push"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"counterparty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"balanceAccountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BA3233T22337JX5JVZFTEPC91B"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"balancePlatform.balanceAccountSweep.created"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In summary, we've covered sweeps using a real-life example and discussed the two types of  sweeps: push and pull. We've shown how to set these up through the Adyen Customer Area or using API calls. Going back to our introduction, Jan now has a better understanding of how this works and he can now feel more confident about the functionality as it allows him just the right amount of control over the payouts for his customers. This means that his users can continue selling and buying cars on his platform without having to worry whether they get their money on time.&lt;/p&gt;

&lt;p&gt;Are you looking for more developer-related content? Have a look at &lt;a href="https://developers.adyen.com"&gt;developers.adyen.com&lt;/a&gt; today or let us know on &lt;a href="https://twitter.com/@AdyenDevs"&gt;Twitter&lt;/a&gt; what you’d like to see next!&lt;/p&gt;

</description>
      <category>adyen</category>
      <category>sweeps</category>
      <category>scheduled</category>
      <category>payouts</category>
    </item>
    <item>
      <title>Using Adyen to Implement Payment Pre-authorizations and Authorization Adjustments</title>
      <dc:creator>Kwok He Chu</dc:creator>
      <pubDate>Wed, 18 Oct 2023 16:43:20 +0000</pubDate>
      <link>https://dev.to/adyen/pre-authorizations-and-authorization-adjustments-for-developers-1ln</link>
      <guid>https://dev.to/adyen/pre-authorizations-and-authorization-adjustments-for-developers-1ln</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This technical blog post explains how developers can implement a hotel booking payment process using Adyen's API. It covers pre-authorizations, amount adjustments, extending authorization expiry dates, capturing payments, refunding payments and webhook payloads.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At Adyen, we understand that modern businesses across different industries require various payment solutions for different use cases. In a basic payment flow, the amount from your payment request is authorized and then captured. But sometimes you may want to change the amount or extend the length of the authorization. This is known as a pre-authorization, followed by an authorization adjustment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The use of authorization adjustment in various industries may differ. One could increase the amount, decrease the amount after a successful pre-authorization or extend the expiry date of the authorization. &lt;/p&gt;

&lt;p&gt;In the hospitality sector, for example, hotels use pre-authorizations to facilitate payment processes before a guest checks into their hotel. During their stay, if the guest incurs additional expenses at the hotel, these expenses can be added to the pre-authorized amount by adjusting the authorization. Once the guest checks out, the hotel captures the final amount or, optionally, cancels the payment if the guest prefers to settle their bill with a different payment method. &lt;/p&gt;

&lt;p&gt;In other cases such as taxi rides, car rentals, or parking, you can use pre-authorizations to handle situations where the final amount for the service is not known at the time of payment. &lt;/p&gt;

&lt;p&gt;Another common use-case is in the United States. As tax regulation can differ widely between states, it is common that the final amount of an order for clothing and apparel deliveries has to be adjusted due to tax regulation changes in applicable tax due to last minute changes of origin or destination of the package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Let’s start by taking a look at a high-level technical overview where a guest reserves a hotel room for $249.99 and chooses to accumulate extra costs during their stay. Here’s an overview of the three main request:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pre-authorization request:&lt;/strong&gt; The merchant initiates a pre-authorization request of $249.99.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization adjustment request:&lt;/strong&gt; Once the pre-authorization is successfully authorized, the merchant sends an authorization adjustment request of $500. 

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Extension request:&lt;/strong&gt; Once a pre-authorization request is successfully authorized, the merchant can optionally extend the authorization to increase the expiry window of this authorization. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capture request:&lt;/strong&gt; Once the authorization adjustment is successful. The merchant confirms the final payment by sending a capture request of $500. This will finalize the payment.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reversal request:&lt;/strong&gt; Optionally, a merchant can cancel or refund the authorization with a reversal request.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Pre-authorization
&lt;/h2&gt;

&lt;p&gt;First, we create a pre-authorization request to the /payments endpoint. We specify a merchant reference to keep track of the payment throughout the whole payment lifecycle. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw7b68m6c35gf9cbnvmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyw7b68m6c35gf9cbnvmw.png" alt="Image of sending a pre-authorization request to the Adyen /payments/ endpoint" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-authorization request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unique&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;reference&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"returnUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-company.example.com/api/handleRedirect?orderRef=7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;We&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;our&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;domain&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"countryCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scheme"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4111111111111111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cvc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"737"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expiryMonth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"03"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expiryYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2023"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"holderName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"John Smith"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow3DS2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authorisationType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PreAuth"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful response contains the “Authorised” result code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-authorization response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"resultCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Authorised"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"brand"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scheme"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adyen will send a webhook asynchronously, check the notification success-flag to see whether the authorization has succeeded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9iexvzivoztu2m7vpc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg9iexvzivoztu2m7vpc3.png" alt="Image of Adyen sending the AUTHORISATION webhook to your endpoint" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"AUTHORISATION" webhook:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"hmacSignature"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="err"&gt;**********************&lt;/span&gt;&lt;span class="s2"&gt;","&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
             &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AUTHORISATION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T15:07:38+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"operations"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"CANCEL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"CAPTURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="s2"&gt;"REFUND"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"052031:1111:03&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="s2"&gt;2030"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The webhook contains a &lt;em&gt;PspReference&lt;/em&gt; that can be used in the subsequent authorization adjustment call.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Authorization Adjustment
&lt;/h2&gt;

&lt;p&gt;To adjust the amount asynchronously, we create a request object to the /payments/&lt;strong&gt;TJ5MXF5SK3RZNN82&lt;/strong&gt;/amountUpdate endpoint. The&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization adjustment request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DelayedCharge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authorization adjustment response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"industryUsage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"delayedCharge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paymentPspReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WBG6F4K25HXXGN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The call is received by Adyen when the response status matches the expected "received" status.&lt;/p&gt;

&lt;p&gt;Later on, Adyen sends a webhook with an “&lt;strong&gt;AUTHORISATION_ADJUSTMENT&lt;/strong&gt;” event code that contains the result of the authorization adjustment. Check the success-flag to see whether the adjustment has been successful and save this accordingly in your backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtf9qguwm4kgq6qorv2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtf9qguwm4kgq6qorv2d.png" alt="Image of Adyen sending the AUTHORISATION_ADJUSTMENT webhook" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"AUTHORISATION_ADJUSTMENT" webhook:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"hmacSignature"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"bookingDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DateTime&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AUTHORISATION_ADJUSTMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T16:01:28+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"originalReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WBG6F4K25HXXGN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validity and authorization expiry dates
&lt;/h2&gt;

&lt;p&gt;Card schemes set specific rules around which businesses (f.e. travel, restaurants, public transportation) are able to adjust an authorization. Your merchant category code (MCC) determines the eligibility, together with the card scheme. You can find an extensive table on availability &lt;a href="https://docs.adyen.com/online-payments/adjust-authorisation/?tab=asynchronous_authorisation_adjustment_1#availability" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Adyen expires authorization requests automatically after 28 days from the day the payment is authorized. Note: Please refer to the &lt;a href="https://docs.adyen.com/online-payments/adjust-authorisation/?tab=asynchronous_authorisation_adjustment_1#validity" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; to see a table as these vary per card scheme. The default expiry period can be adjusted and ensures that Adyen does not automatically expire the authorization after the default 28 days. Our support team can configure this for your merchant account. &lt;/p&gt;

&lt;p&gt;If you try to capture a transaction after the allowed time, it's more likely to fail. However, you can often capture a payment successfully after an authorization has expired. Depending on the card scheme, there can be a fee for late captures, and an increase in interchange and/or scheme fees charged for the transaction. There's also a higher risk of chargebacks from card holders.&lt;/p&gt;

&lt;p&gt;To manually &lt;strong&gt;extend&lt;/strong&gt; the expiry date of an authorization, make a request to the same endpoint but leave the amount unchanged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization adjustment extend request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DelayedCharge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Authorization adjustment extend response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.99&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DelayedCharge"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;“AUTHORIZATION_ADJUSTMENT” extend webhook:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"hmacSignature"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"bookingDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DateTime&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24999&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AUTHORISATION_ADJUSTMENT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T16:21:28+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"originalReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WBG6F4K25HXXGN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Capture
&lt;/h2&gt;

&lt;p&gt;To finalize the payment, make sure you’ve received the webhook for each authorization adjustment that you’ve made. Make a request to the endpoint /payments/&lt;strong&gt;TJ5MXF5SK3RZNN82&lt;/strong&gt;/captures with the final amount of $500 that you wish to capture. Notice that we're using the &lt;em&gt;PspReference&lt;/em&gt; of the initial pre-authorization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capture request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Capture response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"paymentPspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FVNHBFGDFVTFWR82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adyen sends a webhook with the event code “CAPTURE” when successful or unsuccessful. In some rare cases a "&lt;a href="https://docs.adyen.com/online-payments/capture/#failed-capture" rel="noopener noreferrer"&gt;CAPTURE_FAILED&lt;/a&gt;" event code (with a success-flag) can occur as well. This can happen because it was either rejected by a card scheme, technical issue, or when capture expires. For a full list of failed capture reasons, refer to &lt;a href="https://docs.adyen.com/online-payments/capture/failure-reasons/" rel="noopener noreferrer"&gt;this documentation page&lt;/a&gt; on what to do next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphzmvz6vu32nkgz249g3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphzmvz6vu32nkgz249g3.png" alt="Image of Adyen sending the CAPTURE webhook" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Successful “CAPTURE” webhook:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"hmacSignature"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="err"&gt;********************&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"bookingDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;minor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;units&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CAPTURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T16:50:16+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"originalReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"visa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FVNHBFGDFVTFWR82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use an invalid &lt;em&gt;PspReference&lt;/em&gt; (f.e. when you use the &lt;em&gt;PspReference&lt;/em&gt; from an authorization adjustment response), you’ll receive a webhook containing a "transaction not found" message. Likewise, if you attempt to recapture a payment that has already been captured, you will receive an unsuccessful webhook notification with the reason field indicating "Insufficient balance on payment."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unsuccessful “CAPTURE” webhook:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"hmacSignature"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="err"&gt;********************&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"bookingDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"********************"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CAPTURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T16:45:55+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"originalReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WBG6F4K25HXXGN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"N99H9LX8NV5X8N82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reversals&lt;/strong&gt;&lt;br&gt;
To cancel or refund a payment, send a request to the /payments/&lt;strong&gt;TJ5MXF5SK3RZNN82&lt;/strong&gt;/reversals endpoint. Notice that we're still using the &lt;em&gt;PspReference&lt;/em&gt; &lt;strong&gt;TJ5MXF5SK3RZNN82&lt;/strong&gt; from the initial pre-authorization. This request is useful when you want to return the funds to your guest, but are not certain whether the payment has been captured or not.&lt;/p&gt;

&lt;p&gt;This will either: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cancel the payment – in case it has not yet been captured. &lt;/li&gt;
&lt;li&gt;Refund the payment – in case it has already been captured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reversal request:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reversal response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paymentPspReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;original&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pre-authorization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pspReference&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GF445R8G6L2GWR82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"received"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg0fg7prcr0j182m1lh3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwg0fg7prcr0j182m1lh3.png" alt="Image of Adyen sending the CANCEL_OR_REFUND webhook" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“CANCEL_OR_REFUND” webhook&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"live"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"notificationItems"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"NotificationRequestItem"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"additionalData"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"modification.action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"refund"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"CANCEL_OR_REFUND"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"eventDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2023-07-06T17:25:23+02:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"merchantAccountCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MERCHANT_ACCOUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"originalReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"TJ5MXF5SK3RZNN82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;original&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pre-authorization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pspreference&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"paymentMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"mc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"pspReference"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"GF795R5G6L2GWR82"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"true"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we’ve seen the flow, here’s a diagram containing the success scenarios.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foarcfhp6bcu0ospw6i8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foarcfhp6bcu0ospw6i8b.png" alt="Image of the success scenario flow when doing a pre-authorization request" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You send a pre-authorization request to Adyen.&lt;/li&gt;
&lt;li&gt;After some time, Adyen sends an &lt;strong&gt;AUTHORISATION&lt;/strong&gt; webhook.&lt;/li&gt;
&lt;li&gt;A successful &lt;strong&gt;AUTHORISATION&lt;/strong&gt; webhook can be adjusted.

&lt;ul&gt;
&lt;li&gt;(3A) A successful &lt;strong&gt;AUTHORISATION&lt;/strong&gt; webhook can be captured.&lt;/li&gt;
&lt;li&gt;(3B) successful &lt;strong&gt;AUTHORISATION&lt;/strong&gt; webhook can be canceled or. refunded&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A successful &lt;strong&gt;AUTHORISATION_ADJUSTMENT&lt;/strong&gt; webhook can be captured.

&lt;ul&gt;
&lt;li&gt;(4A) A successful &lt;strong&gt;AUTHORISATION_ADJUSTMENT&lt;/strong&gt; webhook can be canceled or refunded.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A successful &lt;strong&gt;CAPTURE&lt;/strong&gt; webhook can be canceled or refunded.&lt;/li&gt;
&lt;li&gt;After receiving a successful &lt;strong&gt;CANCEL_OR_REFUND&lt;/strong&gt; webhook, the refund can still be rejected by the card scheme. There are two webhooks that may be sent afterwards.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;REFUND_FAILED&lt;/strong&gt; webhook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REFUNDED_REVERSED&lt;/strong&gt; webhook.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;"&lt;a href="https://docs.adyen.com/online-payments/refund/#refund-failed" rel="noopener noreferrer"&gt;REFUND_FAILED&lt;/a&gt;" webhook&lt;/strong&gt;&lt;br&gt;
When Adyen sends a successful REFUND webhook, it means that our validations were successful and we sent the refund request to the card scheme. However, the card scheme can still reject the refund. This can happen even a few days after you submitted the refund request. To handle these &lt;a href="https://docs.adyen.com/online-payments/capture/failure-reasons/" rel="noopener noreferrer"&gt;failure reasons&lt;/a&gt;, refer to our documentation on what to do next. &lt;/p&gt;

&lt;p&gt;To test failed refunds, you can make a pre-authorization request and enter the holder name “refund failed”, to test this scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"&lt;a href="https://docs.adyen.com/online-payments/refund/#refunded-reversed" rel="noopener noreferrer"&gt;REFUNDED_REVERSED&lt;/a&gt;" webhook&lt;/strong&gt;&lt;br&gt;
For some payment methods, for example bank transfers, iDEAL, or Bancontact, the status of the payment can change from “&lt;strong&gt;REFUND&lt;/strong&gt;” to “&lt;strong&gt;REFUNDED_REVERSED&lt;/strong&gt;”. This means that the funds have been returned to Adyen, and are back in your account. This can happen, for example, if the bank account is no longer valid. &lt;/p&gt;

&lt;p&gt;Below you can find a full chart of the webhooks with the different event codes. Red indicates that the “success”-flag is set to false, while green indicates that the webhook was successful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flijuwqcb91877nrp5yvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flijuwqcb91877nrp5yvc.png" alt="Flowchart image of the webhooks with event codes that Adyen sends to your application" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find a fully working integration-example on our &lt;a href="https://github.com/adyen-examples/adyen-dotnet-online-payments/tree/main/authorisation-adjustment-example" rel="noopener noreferrer"&gt;Github page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We’ve seen how you can use Adyen &lt;a href="https://docs.adyen.com/online-payments/adjust-authorisation/" rel="noopener noreferrer"&gt;pre-authorizations and authorization adjustments&lt;/a&gt; to implement a hotel booking use case. We’ve gone over the API responses and webhooks that a developer can encounter. The following steps were described in-depth:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Perform the pre-authorization request&lt;/li&gt;
&lt;li&gt;Increase or decrease the amount using authorization adjustments; optionally extend the expiry date of the authorization&lt;/li&gt;
&lt;li&gt;Capture the final amount&lt;/li&gt;
&lt;li&gt;Perform payment reversals (cancel or refund) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’re always looking for ways to improve our existing &lt;a href="https://www.github.com/adyen-examples" rel="noopener noreferrer"&gt;integration examples&lt;/a&gt; or build new integrations for our developers. &lt;/p&gt;

&lt;p&gt;Have a look at &lt;a href="https://developers.adyen.com" rel="noopener noreferrer"&gt;developers.adyen.com&lt;/a&gt; today or let us know on &lt;a href="https://twitter.com/adyendevs" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; what you’d like to see next!&lt;/p&gt;

</description>
      <category>adyen</category>
      <category>preauthorization</category>
      <category>payments</category>
      <category>hotel</category>
    </item>
    <item>
      <title>Building a feature platform guided by your ethos</title>
      <dc:creator>Julien Lengrand-Lambert</dc:creator>
      <pubDate>Wed, 04 Oct 2023 08:06:16 +0000</pubDate>
      <link>https://dev.to/adyen/building-a-feature-platform-guided-by-your-ethos-h4n</link>
      <guid>https://dev.to/adyen/building-a-feature-platform-guided-by-your-ethos-h4n</guid>
      <description>&lt;p&gt;In this blog, we discuss our decision process to build a data platform that is powerful but yet stays guided by our ethos.&lt;/p&gt;

&lt;p&gt;My wife and I are quite different in our shopping habits. She likes analysing the market trends and she’s good at deciding what she likes. She’s even better at deciding whether to buy or not — disclaimer: usually she does buy it, and then our entrance at home looks like a package pick-up point (not true, but also not entirely not-true).&lt;/p&gt;

&lt;p&gt;I, however, have a different poison. When I am looking for something, say a new set of headphones, I analyse and analyse again, and at some point I conclude that a certain product is probably the best fit for what I am looking for. Then, I check, yet again, the distance for the second choice and after that I might end up going back to the fundamental question of whether I actually needed it in the first place.&lt;/p&gt;

&lt;p&gt;I am quite frugal, so if I am not very enthusiastic about the top choice I will probably end up discarding it (and bloating those non-conversion metrics for the A/B test behind the ecommerce site that leaves the team scratching their head about what is wrong with their website).&lt;/p&gt;

&lt;p&gt;In my defence I will say that if I am sure I need something and there is a clear market winner, I buy immediately and I do not think about it anymore.&lt;/p&gt;

&lt;p&gt;The point is, choosing what to buy and when to buy it, is quite transcendental. Choosing your tech stack is a somehow similar problem. You need to understand and reflect very well on a number of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether you actually need it, or is a fun exciting but limited-value exercise (hello ChatGPT demos 🙊)&lt;/li&gt;
&lt;li&gt;How do you sweep and track the market and assess which tool or framework to adopt?&lt;/li&gt;
&lt;li&gt;Should you build or buy?&lt;/li&gt;
&lt;li&gt;How fast do you need it and whether you are sacrificing something instead?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without thorough consideration of the above, a leadership team (often proud of their choice and/or invested in another way) may spiral the team downwards in terms of productivity and motivation. That’s why it is important to give it the right amount of love, and eventually make a well-informed choice together with the technical experts.&lt;/p&gt;

&lt;p&gt;It is remarkably difficult if you end up in a situation where there’s a clear need for something better than what you have now but there is no industry standard or a clear choice. That’s where my shopper-persona would collapse, and a Feature Store, or should I say Platform (will come to that later), has been a primary example of this sort of conundrum. At Adyen we have gone through this exercise a number of times and we have learned, sometimes the hard way, how to go about these choices. It really boils down to two things that we embrace in our ethos: iterating and control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our first attempt to build a Feature Store
&lt;/h2&gt;

&lt;p&gt;Let me use an example of a use case for a feature store at Adyen. Every payment that goes through Adyen — and we do a lot of those (860 billions USD in 2022) — undertakes a journey where a number of decisions are made through an inference service fueled by a machine learning model that we have trained and deployed. We have a few instances of those services with different purposes: our risk system (is the transaction fraud or legit), our authentication service (should we authenticate the user, and if so in which way), our routing algorithm, our transaction optimiser, our retry logic and others.&lt;/p&gt;

&lt;p&gt;We are talking about a service that can take several thousands of requests per second per model and respond in less than 100 ms. The final goal of all these models is to land as many good transactions as possible in the most efficient way, without ending up in a chargeback or a retry or higher costs.&lt;/p&gt;

&lt;p&gt;Now, these models need features, of course. They need features both at training time and at scoring time.&lt;/p&gt;

&lt;p&gt;Let’s zoom in on the risk system. The service was initially built through rules across three different data sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Block/allow look-up-tables, powered by PostgreSQL.&lt;/li&gt;
&lt;li&gt;Velocity database, powered by PostgreSQL, and able to provide information such as how many times has this card been used in this last minute.&lt;/li&gt;
&lt;li&gt;Our “shopper” database, also powered by PostgreSQL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The “shopper” database deserves its own paragraph. We have used, and maybe even abused, PostgreSQL in a very beautiful way: to identify shoppers in real time. This system in the end provides an elegant and simple graph algorithm by identifying communities of attributes (cards, emails, …) that relate to the same person. It does that very efficiently and very fastly, but it has its own complications around flexibility and scalability. My colleague Burak &lt;a href="https://www.adyen.com/blog/the-adyen-way-of-engineering-oss-or-built-in-house" rel="noopener noreferrer"&gt;wrote a great article about it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When introducing a new approach based on a supervised classifier, we thought: hey, let’s include features about the merchant, that’ll boost AUCPR. Small note, a merchant in the fintech jargon is a seller or a company, take for example, Uber or Spotify. In this sense then, we’d include, as a feature, datapoints like the size of the merchant, the country of the merchant, for how long have we been processing for this merchant, the authorisation rate of that merchant across different sliding windows and so on.&lt;/p&gt;

&lt;p&gt;However, many of these example features are slow-moving, medium cardinality, high data volume, features. And PostgreSQL wasn’t gonna cut it in terms of crunching all that volume. So we added a new database called “Feature Store” (read that as Dr. Evil with his famous quote hands).&lt;/p&gt;

&lt;p&gt;We took advantage of the fact that we were sending all our transaction events to our Big Data Platform via Kafka. We collect all this info in the form of Hive tables and then we use Spark to crunch all this information, all beautifully orchestrated through Airflow. We had all this information and tooling available in our Big Data Platform because that’s where we train our models. We just need to use an abstraction layer to define the features (we chose Feast) and then deploy on another posgresql instance in the real-time flow (we love postgresql, in case you haven’t figured this out yet). The ML artifacts are deployed to our real-time platform through our wrapper around MLflow, called Alfred, that allows us to stage their rollout into ghost, test, canary live settings and default live modes.&lt;/p&gt;

&lt;p&gt;The final picture to our first crack at a “Feature Store” looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba82uelwor9tiuo3zeen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fba82uelwor9tiuo3zeen.png" alt="Image description" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And happy we were ever after, thinking that we had a “Feature Store”. And by “ever after” I mean a couple of months.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build-vs-buy tradeoff
&lt;/h2&gt;

&lt;p&gt;Hidden in all this there’s something that might have passed unnoticed, the redux of a very important lesson that we have learned through the years: our build-vs-buy trade-off.&lt;/p&gt;

&lt;p&gt;There are great vendors that promise and deliver a seamless turn-key experience: it’s fast and it just “works”. It’s a very amenable choice, and I can only show my honest respect for these startups: they are like rain in the middle of a drought for a lot of companies that want to instantly get in the gig of Feature Stores, MLOps, Experimentation, Data Governance and any other sweet problem to solve. And they do a good job at it.&lt;/p&gt;

&lt;p&gt;At Adyen, we like to stay in control and understand what happens under the hood. We also have a very solid principle: we won’t use a vendor for anything touching our core business. In this case, processing a payment is indeed core business and we don’t want to introduce a dependency on a third-party. That has two important implications that are worth calling out:&lt;/p&gt;

&lt;p&gt;First, we do use vendors, but we are critical about which part of the system they impact. On the one hand we buy our laptops from a vendor — it wouldn’t be optimal if we had a team building laptops. On the other hand, because we are set in building for the long term, we believe in controlling all our supply-chain (take SpaceX, procuring their own screws even).&lt;/p&gt;

&lt;p&gt;Second. If we don’t use vendors, do we then build in-house? We have made that choice in the past, and now in perspective, it was a mistake. Picture a top-performing engineer, machete in their teeth, mumbling a classical “hold my beer” and then proceeding to build from scratch something that already exists because “it will only take me a week to do it better”.&lt;/p&gt;

&lt;p&gt;We have been there and after the first month I can guarantee the fun is over. Looking ahead at the feature parity roadmap sinks you in despair, the operational debt and preventable bugs itch you more than usual, and you end up going to bed every night thinking “why did we do this”.&lt;/p&gt;

&lt;p&gt;So what’s the answer?&lt;/p&gt;

&lt;p&gt;Well, open source.&lt;/p&gt;

&lt;p&gt;We use open source as much as possible to build our infra and rails, and then we build on top of it our core business. We also contribute back by merging PRs and adding new features that we found useful. At the end of the day, the internet runs on open source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iterating on the Feature Store
&lt;/h2&gt;

&lt;p&gt;I already gave away one bit of our ethos: strong control of our dependencies, fueled by long-term thinking. A second big trait of our way of thinking is the iteration culture.&lt;/p&gt;

&lt;p&gt;At some point when building software, and even hardware systems, someone figured out that working in waterfall contracts doesn’t really help and that instead working in an agile way gets you further and faster, and it is also more fun. The point of agile is not to adopt scrum. The point of agile is to embrace that the MVP is minimum (and therefore rusty and barely presentable) and also viable (it works, it’s not a WIP commit), and from there onwards, you have to iterate and quickly.&lt;/p&gt;

&lt;p&gt;We took a cold look at what we had built that we proudly called “feature store”, tried to remove any emotional attachments to it, and ended up concluding that it wasn’t actually great. We also conclude that we might want to do some soul-searching and write a requirement list about what we want the whole thing to do.&lt;/p&gt;

&lt;p&gt;We ended up with a letter to Santa with everything we wanted. At least from there we could make a conscious choice about what we will not get given the cost and possibilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature Parity: the features and values on the training and scoring flows must be identical.&lt;/li&gt;
&lt;li&gt;Retrieval latency: we need the inference service to work under 100 ms, so there’s that.&lt;/li&gt;
&lt;li&gt;Recency: the features should not be old, we should be able to refresh them very fast.&lt;/li&gt;
&lt;li&gt;Cardinality: we want to be able to store billions of features.&lt;/li&gt;
&lt;li&gt;Distributed: we need instances of the feature store around the world, because we process globally.&lt;/li&gt;
&lt;li&gt;Storage / Scalability: our transaction volume grows quite a lot every year, and we build for 20x.&lt;/li&gt;
&lt;li&gt;Availability / Uptime: we need the system to be there 99.99999% of the time.&lt;/li&gt;
&lt;li&gt;Self-service: ideally we want data scientists to go about themselves when prototyping and deploying new features&lt;/li&gt;
&lt;li&gt;Complex calculation: some of these features can be complex to compute, that should be alright.&lt;/li&gt;
&lt;li&gt;Feature diversity: it’d be great if we didn’t have to maintain three different databases and we just had one endpoint with all sorts of data inside.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After seeing that list we thought “wow, it’s a long list” but we also figured that there was an underlying difference between a pure storage place and a place where things are computed. And that’s also where we read &lt;a href="https://huyenchip.com/2023/01/08/self-serve-feature-platforms.html" rel="noopener noreferrer"&gt;Chip Huygen’s fantastic article on Feature Platforms&lt;/a&gt;, and it was one of those click/a-ha moments, when you confidently say out loud “we were building a feature platform, not a feature store” and you can hear the non-existent triumphant music behind you.&lt;/p&gt;

&lt;p&gt;The main difference lies in facilitating the computing of features, apart from the storing and serving which is indeed captured under the definition of the feature store.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new blueprint
&lt;/h2&gt;

&lt;p&gt;Based on this we also saw the need to have a system that spans across two different platforms, our real-time platform (where payments, KYC, payouts, refunds and financial interactions with the world happen) and our big data platform (where we crunch the data). That’s not a surprise given that you have a need in two very different flows: your inference flow in real-time and your training flow off-line.&lt;/p&gt;

&lt;p&gt;We needed an abstraction layer that would glue both systems and we chose to keep on using Feast, the open source package to allow data scientists and engineers to define features uniquely and ensure consistency across the two environments. We also evaluated LinkedIn’s Feather, but we deemed it too opinionated and opted for the openness of Feast.&lt;/p&gt;

&lt;p&gt;The general idea behind the synching happening on the two environments is that some features will be computed on the real time flow and stored on hot storage and sync back to the cold storage (big data platform) while the slow-moving features will be computed on the big data platform, stored there (cold storage) and synched to the hot storage for inference.&lt;/p&gt;

&lt;p&gt;While the batch computation engine and storage were already there, Spark and Hive/Spark/Delta, we still had a few choices to make regarding the on-line flow. For stream computing we are inclined to use Apache Flink — but we can define it later. For the storage layer we hit a dilemma across a few contenders: Redis, Cassandra, Cockroach and sweet old posgresql.&lt;/p&gt;

&lt;p&gt;Here is where I will circle back to where I started: you need to make good decisions and that probably means that you need to involve technical experts. Even there, you also want to be able to tap into the wider organisation to make sure that you are not too biassed or forgetting anything. That’s why we have a TechRadar procedure where engineers can share ideas for technology contenders, spar, benchmark and eventually decide on which to adopt in a “makes sense” fashion.&lt;/p&gt;

&lt;p&gt;We decided for Cassandra. Redis’ in-memory storage makes it quite expensive at the cardinality we are looking for, Cockroach is really keen on read-write consistency at the expense of speed and posgresql, well, didn’t cut it for our needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F275g7b6gluu04l8e5w35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F275g7b6gluu04l8e5w35.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We still are evaluating choices for on-line computing engines (as said, Flink looks good) and feature monitoring, where it might be that we just use the monitoring stack available, largely consisting of Prometheus, Elastic and Grafana.&lt;/p&gt;

&lt;p&gt;That’s an honest look at where we are today. We are making an informed choice and not shooting from the hip. We have determined what we need, we have also determined what is important to us and what we are willing to pay for it. We have analysed the market and open-source offering and are back to our beloved execution mode.&lt;/p&gt;

&lt;p&gt;Even if there’s no clear and obvious choice, my shopper persona is still happily going through this procurement journey and enjoying the benefits of learning, discovering the possibilities and deciding. Because if we don’t get it right at first, we will build, fail, learn and iterate.&lt;/p&gt;

</description>
      <category>database</category>
      <category>datascience</category>
      <category>platforms</category>
      <category>ai</category>
    </item>
    <item>
      <title>Guide: Upgrade and customization for Salesforce Commerce Cloud cartridge</title>
      <dc:creator>Ayodeji Ogundare</dc:creator>
      <pubDate>Fri, 01 Sep 2023 13:52:28 +0000</pubDate>
      <link>https://dev.to/adyen/guide-upgrade-and-customization-for-salesforce-commerce-cloud-cartridge-4b51</link>
      <guid>https://dev.to/adyen/guide-upgrade-and-customization-for-salesforce-commerce-cloud-cartridge-4b51</guid>
      <description>&lt;p&gt;In this guide, discover the importance and process of upgrading your &lt;a href="https://github.com/Adyen/adyen-salesforce-commerce-cloud/releases"&gt;Salesforce Commerce Cloud (SFCC) cartridge&lt;/a&gt; to the latest version to create a hassle-free integration and seamless checkout experience benefitting both you and your customers. We'll highlight best practices for customizations and walk you through the process of adding custom code to a new cartridge, ensuring a smooth transition to the latest releases.&lt;/p&gt;

&lt;p&gt;As an online business owner, ensuring a smooth and seamless checkout experience for your shoppers is vital to success. To achieve this, customizations are often necessary to tailor your checkout process to meet specific needs. To take advantage of new features, bug fixes, and security patches, you’ll need to stay up-to-date with the latest cartridge version.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;This guide is specifically tailored to users of the Salesforce Commerce Cloud Storefront Reference Architecture (SFRA). If your e-commerce platform does not utilize SFRA, some of the outlined steps and procedures may not be directly applicable.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits of upgrading your cartridge
&lt;/h2&gt;

&lt;p&gt;Upgrading your cartridge to the &lt;a href="https://github.com/Adyen/adyen-salesforce-commerce-cloud/releases"&gt;latest version&lt;/a&gt; offers several benefits that can significantly enhance your checkout experience. Here's why you should consider upgrading:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Access to new features: Each cartridge release comes with exciting new features that can improve the overall functionality and usability of your checkout process. This ensures that you offer your customers the best shopping experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bug fixes and security patches: As with any software, cartridges might have bugs or security vulnerabilities. Regular updates and upgrades address these issues, not only ensuring that your checkout process remains secure, but also improving the authorization rate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compatibility with integrations: Third-party integrations and platforms continually evolve, and cartridge updates often ensure compatibility with the latest versions of these integrations. Upgrading your cartridge reduces the risk of conflicts and ensures a seamless connection with your preferred tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Continued Cartridge support: We provide support and assistance for the latest versions, making it easier to troubleshoot issues and seek guidance whenever needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Customization guide for smoother upgrade (SFRA)
&lt;/h2&gt;

&lt;p&gt;Merchants use customizations to communicate their brand value to shoppers. Customizations are a great way to offer a unique shopper experience. Unfortunately, if customizations are implemented inside of the cartridge, they obscure future cartridge upgrades and introduce technology bottlenecks. We've created a &lt;a href="https://help.adyen.com/academy/how-to-videos/plugins/how-to-customize-your-sfcc-cartridge"&gt;4-minute video&lt;/a&gt; to help you decouple your customizations and upgrade a customized cartridge to the latest version. You can skip the &lt;a href="https://help.adyen.com/academy/how-to-videos/plugins/how-to-customize-your-sfcc-cartridge"&gt;video&lt;/a&gt; if you prefer a step-by-step text guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add custom code to a new cartridge
&lt;/h3&gt;

&lt;p&gt;To make future upgrades and troubleshooting easier, add your custom code to the &lt;strong&gt;int_custom_cartridge&lt;/strong&gt; &lt;a href="https://github.com/Adyen/adyen-salesforce-commerce-cloud/tree/main/src/cartridges/int_custom_cartridge"&gt;folder&lt;/a&gt; in your &lt;strong&gt;src/cartridges&lt;/strong&gt; directory. If this folder is not available in your version, create a new folder and name it; &lt;strong&gt;int_custom_cartridge&lt;/strong&gt; and add your custom code. This setup will allow you to temporarily remove custom code during upgrades or troubleshooting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Add your custom code to the int_custom_cartridge folder
# Modify the code as needed to customize the checkout experience. For example, in JavaScript:

# File: int_custom_cartridge/scripts/customization.js

function customizeCheckout() {
  // Your custom code here
  console.log("Custom checkout code executed.");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Include custom cartridge in package.json file
&lt;/h3&gt;

&lt;p&gt;Update the name property in the &lt;strong&gt;package.json&lt;/strong&gt; file to &lt;strong&gt;int_custom_cartridge&lt;/strong&gt; or the name you chose for your custom cartridge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Update package.json to support the custom cartridge
# File: int_custom_cartridge/package.json
{
  "name": "int_custom_cartridge",
  "version": "1.0.0",
  "description": "Custom cartridge for checkout customization",
  // Other package.json properties
}

# Update root package.json to contain the new cartridge in the build step
# Make sure you are in the root directory of your project and run

npm install
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Add the new cartridge to your cartridge path
&lt;/h3&gt;

&lt;p&gt;In the Business Manager, navigate to &lt;strong&gt;Administration&lt;/strong&gt; &amp;gt; &lt;strong&gt;Sites&lt;/strong&gt; &amp;gt; &lt;strong&gt;Manage Sites&lt;/strong&gt; &amp;gt; &lt;strong&gt;[yourSite]&lt;/strong&gt; &amp;gt; &lt;strong&gt;Settings&lt;/strong&gt;. In the Cartridges field, add the new cartridge before the Adyen cartridges. Click “&lt;strong&gt;Apply&lt;/strong&gt;” to save your changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Modify or add end-to-end tests (optional)
&lt;/h3&gt;

&lt;p&gt;To ensure your custom code works correctly, modify or add end-to-end tests as needed. Running these tests will validate the functionality of your customizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade guide for different integrations
&lt;/h2&gt;

&lt;p&gt;Depending on your integration type (Default or Customized), the upgrade process varies:&lt;/p&gt;

&lt;h3&gt;
  
  
  Default integration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check which SFRA version is required for the upgrade and migrate if necessary, aiming to use the highest available SFRA version&lt;/li&gt;
&lt;li&gt;Download the desired Adyen cartridge version from &lt;a href="https://github.com/Adyen/adyen-salesforce-commerce-cloud"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Transpile, compile, and upload the compatible, auto-generated code using &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Re-upload the metadata
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Download the desired Adyen cartridge version from GitHub
# Replace '23.1.0' with the version you want to upgrade to
git clone https://github.com/adyen/adyen-salesforce-commerce-cloud.git --branch 23.1.0

# Re-upload the metadata
# Make sure you are in the root directory of your project
cd adyen-salesforce-commerce-cloud

# Transpile, compile, and upload the compatible, auto-generated code
npm run build

# Zip the site_import folder
zip -r adyen_integration.zip package/metadata/site_import/sites

# In Business Manager, go to Administration &amp;gt; Site Development &amp;gt; Site Import &amp;amp; Export
# Import the zipped file (site_import.zip)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Customized integration
&lt;/h3&gt;

&lt;p&gt;For a quick demo of how to upgrade the SFCC cartridge with customization, watch this &lt;a href="https://help.adyen.com/academy/how-to-videos/plugins/how-to-upgrade-sfcc-with-customization"&gt;2 mins video&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extract any custom code from the cartridge and place it in the custom cartridge (int_custom_cartridge) folder. Create a new folder if not available in your version.&lt;/li&gt;
&lt;li&gt;Check SFRA version requirements and migrate if needed&lt;/li&gt;
&lt;li&gt;Download the desired Adyen cartridge version from GitHub&lt;/li&gt;
&lt;li&gt;Update the package.json as explained above and run npm run build&lt;/li&gt;
&lt;li&gt;Re-upload the metadata&lt;/li&gt;
&lt;li&gt;Update the cartridge path in the Business Manager to include your customizations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In today's competitive e-commerce landscape, the checkout experience can make or break a customer's decision to complete a purchase. As an online business owner, customizing your checkout process is essential to cater to your unique requirements and create a branded experience that resonates with your audience. However, these customizations must not come at the cost of missing out on crucial updates and improvements.&lt;/p&gt;

&lt;p&gt;By following this guide to upgrading your cartridge to the latest version, you can strike the perfect balance between customization and innovation. Embrace the latest features, bug fixes, and security patches to ensure a seamless and secure checkout journey for your shoppers.&lt;/p&gt;

&lt;p&gt;Upgrading your cartridge to the latest version is more than just a technical necessity - it's an investment in your business's success. Stay ahead of the competition by accessing new capabilities that improve the functionality of your checkout process and enhance customer satisfaction. Take your e-commerce venture one step closer to excellence.&lt;/p&gt;

&lt;p&gt;So, are you ready to unlock the full potential of your checkout process? Your dedication to providing the best checkout experience will not only increase conversion rates but also foster customer loyalty.&lt;/p&gt;

&lt;p&gt;Upgrade today and let your checkout experience set the gold standard for online shopping!&lt;/p&gt;

</description>
      <category>sfcc</category>
      <category>onlinepayments</category>
      <category>tech</category>
      <category>ecommerce</category>
    </item>
  </channel>
</rss>
