DEV Community

Cover image for Using Adyen to Implement Payment Pre-authorizations and Authorization Adjustments
Kwok He Chu for Adyen

Posted on • Edited on

Using Adyen to Implement Payment Pre-authorizations and Authorization Adjustments

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.

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.

Introduction

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.

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.

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.

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.

Overview

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:

  1. Pre-authorization request: The merchant initiates a pre-authorization request of $249.99.
  2. Authorization adjustment request: Once the pre-authorization is successfully authorized, the merchant sends an authorization adjustment request of $500.
    • Extension request: Once a pre-authorization request is successfully authorized, the merchant can optionally extend the authorization to increase the expiry window of this authorization.
  3. Capture request: Once the authorization adjustment is successful. The merchant confirms the final payment by sending a capture request of $500. This will finalize the payment.
    • Reversal request: Optionally, a merchant can cancel or refund the authorization with a reversal request.

1. Pre-authorization

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.

Image of sending a pre-authorization request to the Adyen /payments/ endpoint

Pre-authorization request:

{
  "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
  "reference": "7a5d8be7-cceb-4442-b17f-3a10a8fa396d", // Your unique reference
  "channel": "Web",
  "amount": {
    "currency": "USD",
    "value": 24999 // 249.99 USD in minor units
  },
  "returnUrl": "https://your-company.com/api/handleRedirect?orderRef=7a5d8be7-cceb-4442-b17f-3a10a8fa396d", // We redirect to our domain
  "countryCode": "NL",
  "paymentMethod": { 
     "type": "scheme",
      "number":"4111111111111111",
      "cvc":"737",
      "expiryMonth":"03",
      "expiryYear":"2023",
      "holderName":"John Smith"
  },
  "additionalData": {
    "allow3DS2": "true",
    "authorisationType": "PreAuth"
  }
}
Enter fullscreen mode Exit fullscreen mode

A successful response contains the “Authorised” result code.

Pre-authorization response:

{
   "additionalData" : {
      // 
   },
   "pspReference" : "TJ5MXF5SK3RZNN82",
   "resultCode" : "Authorised",
   "amount" : {
      "currency" : "USD",
      "value" : 24999 // 249.99 USD in minor units
   },
   "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
   "paymentMethod" : {
      "brand" : "visa",
      "type" : "scheme"
   }
}
Enter fullscreen mode Exit fullscreen mode

Adyen will send a webhook asynchronously, check the notification success-flag to see whether the authorization has succeeded.

Image of Adyen sending the AUTHORISATION webhook to your endpoint

"AUTHORISATION" webhook:

{
   "live" : "false",
   "notificationItems" : [
      {
         "NotificationRequestItem" : {
            "additionalData" : {
      // 
               "hmacSignature" : ""**********************",",
             // 
            },
            "amount" : {
               "currency" : "USD",
               "value" : 24999 // 249.99 USD in minor units
            },
            "eventCode" : "AUTHORISATION",
            "eventDate" : "2023-07-06T15:07:38+02:00",
            "merchantAccountCode" : "YOUR_MERCHANT_ACCOUNT",
            "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
            "operations" : [
               "CANCEL",
               "CAPTURE",
               "REFUND"
            ],
            "paymentMethod" : "visa",
            "pspReference" : "TJ5MXF5SK3RZNN82",
            "reason" : "052031:1111:03\/2030",
            "success" : "true"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

The webhook contains a PspReference that can be used in the subsequent authorization adjustment call.

2. Authorization Adjustment

To adjust the amount asynchronously, we create a request object to the /payments/TJ5MXF5SK3RZNN82/amountUpdate endpoint. The

Authorization adjustment request:

{
  "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
  "amount": {
    "Currency": "USD",
    "Value": 50000 // 500 USD in minor units
  },
  "Reason": "DelayedCharge",
  "reference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d"
}
Enter fullscreen mode Exit fullscreen mode

Authorization adjustment response:

{
    "industryUsage": "delayedCharge",
    "status": "received",
    "amount": {
        "currency": "USD",
        "value": 50000
    },
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
    "paymentPspReference": "TJ5MXF5SK3RZNN82",
    "pspReference": "WBG6F4K25HXXGN82",
    "reference": "7a5d8be7-cceb-4442-b17f-3a10a8fa396d"
}
Enter fullscreen mode Exit fullscreen mode

The call is received by Adyen when the response status matches the expected "received" status.

Later on, Adyen sends a webhook with an “AUTHORISATION_ADJUSTMENT” 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.

Image of Adyen sending the AUTHORISATION_ADJUSTMENT webhook

"AUTHORISATION_ADJUSTMENT" webhook:

{
   "live" : "false",
   "notificationItems" : [
      {
         "NotificationRequestItem" : {
            "additionalData" : {
               "hmacSignature" : "********************",
               "bookingDate" : "********************" // This is a DateTime
            },
            "amount" : {
               "currency" : "USD",
               "value" : 50000
            },
            "eventCode" : "AUTHORISATION_ADJUSTMENT",
            "eventDate" : "2023-07-06T16:01:28+02:00",
            "merchantAccountCode" : "YOUR_MERCHANT_ACCOUNT",
            "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
            "originalReference" : "TJ5MXF5SK3RZNN82",
            "paymentMethod" : "visa",
            "pspReference" : "WBG6F4K25HXXGN82",
            "reason" : "",
            "success" : "true"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

Validity and authorization expiry dates

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 here.

Adyen expires authorization requests automatically after 28 days from the day the payment is authorized. Note: Please refer to the documentation 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.

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.

To manually extend the expiry date of an authorization, make a request to the same endpoint but leave the amount unchanged.

Authorization adjustment extend request:

{
  "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
  "amount": {
    "Currency": "USD",
    "Value": 24999 // 249.99 USD in minor units
  },
  "Reason": "DelayedCharge",
  "reference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d"
}
Enter fullscreen mode Exit fullscreen mode

Authorization adjustment extend response:

{
  "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
  "amount": {
    "Currency": "USD",
    "Value": 24999 // 249.99 USD in minor units
  },
  "Reason": "DelayedCharge",
  "reference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d"
}
Enter fullscreen mode Exit fullscreen mode

“AUTHORIZATION_ADJUSTMENT” extend webhook:

{
   "live" : "false",
   "notificationItems" : [
      {
         "NotificationRequestItem" : {
            "additionalData" : {
               "hmacSignature" : "********************",
               "bookingDate" : "********************" // This is a DateTime
            },
            "amount" : {
               "currency" : "USD",
               "value" : 24999
            },
            "eventCode" : "AUTHORISATION_ADJUSTMENT",
            "eventDate" : "2023-07-06T16:21:28+02:00",
            "merchantAccountCode" : "YOUR_MERCHANT_ACCOUNT",
            "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
            "originalReference" : "TJ5MXF5SK3RZNN82",
            "paymentMethod" : "visa",
            "pspReference" : "WBG6F4K25HXXGN82",
            "reason" : "",
            "success" : "true"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

3. Capture

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/TJ5MXF5SK3RZNN82/captures with the final amount of $500 that you wish to capture. Notice that we're using the PspReference of the initial pre-authorization.

Capture request:

{
  "merchantAccount":"YOUR_MERCHANT_ACCOUNT",
       "amount":{
          "Currency": "USD",
          "Value": 50000 // 500 USD in minor units
       },
   "reference":"7a5d8be7-cceb-4442-b17f-3a10a8fa396d"
}
Enter fullscreen mode Exit fullscreen mode

Capture response:

{
   "merchantAccount" : "YOUR_MERCHANT_ACCOUNT",
   "paymentPspReference" : "TJ5MXF5SK3RZNN82",
   "pspReference" : "FVNHBFGDFVTFWR82",
   "reference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
   "status" : "received",
   "amount" : {
      "currency" : "USD",
      "value" : 50000 // 500 USD in minor units
   }
}
Enter fullscreen mode Exit fullscreen mode

Adyen sends a webhook with the event code “CAPTURE” when successful or unsuccessful. In some rare cases a "CAPTURE_FAILED" 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 this documentation page on what to do next.

Image of Adyen sending the CAPTURE webhook

Successful “CAPTURE” webhook:

{
   "live" : "false",
   "notificationItems" : [
      {
         "NotificationRequestItem" : {
            "additionalData" : {
               "hmacSignature" : ""********************"",
               "bookingDate" : "********************"
            },
            "amount" : {
               "currency" : "USD",
               "value" : 50000 // 500 USD in minor units
            },
            "eventCode" : "CAPTURE",
            "eventDate" : "2023-07-06T16:50:16+02:00",
            "merchantAccountCode" : "YOUR_MERCHANT_ACCOUNT",
            "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
            "originalReference" : "TJ5MXF5SK3RZNN82",
            "paymentMethod" : "visa",
            "pspReference" : "FVNHBFGDFVTFWR82",
            "reason" : "",
            "success" : "true"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

If you use an invalid PspReference (f.e. when you use the PspReference 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."

Unsuccessful “CAPTURE” webhook:

{
   "live" : "false",
   "notificationItems" : [
      {
         "NotificationRequestItem" : {
            "additionalData" : {
               "hmacSignature" : ""********************"",
               "bookingDate" : "********************"
            },
            "amount" : {
               "currency" : "USD",
               "value" : 50000
            },
            "eventCode" : "CAPTURE",
            "eventDate" : "2023-07-06T16:45:55+02:00",
            "merchantAccountCode" : "YOUR_MERCHANT_ACCOUNT",
            "merchantReference" : "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
            "originalReference" : "WBG6F4K25HXXGN82",
            "pspReference" : "N99H9LX8NV5X8N82",
            "reason" : "Transaction not found",
            "success" : "false"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

Reversals
To cancel or refund a payment, send a request to the /payments/TJ5MXF5SK3RZNN82/reversals endpoint. Notice that we're still using the PspReference TJ5MXF5SK3RZNN82 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.

This will either:

  • Cancel the payment – in case it has not yet been captured.
  • Refund the payment – in case it has already been captured.

Reversal request:

{
    "reference": "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT"
}
Enter fullscreen mode Exit fullscreen mode

Reversal response:

{
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
    "paymentPspReference": "TJ5MXF5SK3RZNN82", // The original pre-authorization pspReference
    "pspReference" : "GF445R8G6L2GWR82",
    "reference": "7a5d8be7-cceb-4442-b17f-3a10a8fa396d",
    "status" : "received"
}
Enter fullscreen mode Exit fullscreen mode

Image of Adyen sending the CANCEL_OR_REFUND webhook

“CANCEL_OR_REFUND” webhook

{
   "live":"false",
   "notificationItems":[
      {
         "NotificationRequestItem":{
            "additionalData":{
               "modification.action": "refund"
            },
            "amount":{
               "currency": "USD",
               "value": 50000
            },
            "eventCode":"CANCEL_OR_REFUND",
            "eventDate":"2023-07-06T17:25:23+02:00",
            "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT",
            "originalReference":"TJ5MXF5SK3RZNN82", // The original pre-authorization pspreference
            "paymentMethod":"mc",
            "pspReference":"GF795R5G6L2GWR82",
            "reason":"",
            "success":"true"
         }
      }
   ]
}
Enter fullscreen mode Exit fullscreen mode

Now that we’ve seen the flow, here’s a diagram containing the success scenarios.

Image of the success scenario flow when doing a pre-authorization request

  1. You send a pre-authorization request to Adyen.
  2. After some time, Adyen sends an AUTHORISATION webhook.
  3. A successful AUTHORISATION webhook can be adjusted.
    • (3A) A successful AUTHORISATION webhook can be captured.
    • (3B) successful AUTHORISATION webhook can be canceled or. refunded
  4. A successful AUTHORISATION_ADJUSTMENT webhook can be captured.
    • (4A) A successful AUTHORISATION_ADJUSTMENT webhook can be canceled or refunded.
  5. A successful CAPTURE webhook can be canceled or refunded.
  6. After receiving a successful CANCEL_OR_REFUND webhook, the refund can still be rejected by the card scheme. There are two webhooks that may be sent afterwards.
    • REFUND_FAILED webhook.
    • REFUNDED_REVERSED webhook.

"REFUND_FAILED" webhook
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 failure reasons, refer to our documentation on what to do next.

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

"REFUNDED_REVERSED" webhook
For some payment methods, for example bank transfers, iDEAL, or Bancontact, the status of the payment can change from “REFUND” to “REFUNDED_REVERSED”. 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.

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.

Flowchart image of the webhooks with event codes that Adyen sends to your application

You can find a fully working integration-example on our Github page.

Summary

We’ve seen how you can use Adyen pre-authorizations and authorization adjustments 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:

  1. Perform the pre-authorization request
  2. Increase or decrease the amount using authorization adjustments; optionally extend the expiry date of the authorization
  3. Capture the final amount
  4. Perform payment reversals (cancel or refund)

We’re always looking for ways to improve our existing integration examples or build new integrations for our developers.

Have a look at developers.adyen.com today or let us know on Twitter what you’d like to see next!

Top comments (0)