Search

Are you looking for test card numbers?

Would you like to contact support?

Omnichannel icon

Cross-channel transactions

Manage transactions across sales channels and offer your online inventory in store.

See how others have done it

Stores like Peak Performance use endless aisle kiosks to boost their in-store inventory, and prevent lost sales.

Find out more on our blog.

When you process payments for all your sales channels through the Adyen payments platform, you can use one set of APIs to capture, cancel, and refund payments—from any of your sales channels, or your Order Management System (OMS), call center, distribution center, or warehouse.

In this tutorial, we'll show you how you can capture payments from any channel, offer cross-channel returns, and save a sale when an item is out of stock in store by offering your full product inventory.

Unique identifier for transactions

Adyen assigns a unique identifier for all transactions, known as a PSP reference. You'll use this identifier to manage transactions across sales channels. Store this identifier so that you can track payments, refer to the original payment if you want to capture, cancel, or refund them, and validate if your request has been successful.

The next sections describe use cases in detail.

Before you begin

To implement cross-channel use cases, make sure that:

  1. You can create customer profiles and recognize returning customers across your sales channels.
  2. If you haven't done so already, we recommend that you use one of our server-side libraries to connect to Adyen APIs for capturing, cancelling, and refunding payments.

Capture on fulfillment

If your customers pay for goods or services that they don't immediately receive, consider capturing the payments on fulfillment. This means that you'll charge your customer when they collect or receive the goods, or they make use of your service.

When you capture on fulfillment, payments are completed in two steps:

  1. You place a hold on the customer's card. This is called an authorisation, and reserves the funds for the transaction.
  2. On fulfillment, you complete the payment. This is called a capture, which transfers the funds from the customer to your account.

For more information about separate captures, see our Capture documentation.

Before you can make a separate capture, you first need to configure how payments are captured for your merchant account.

Configure separate manual capture

By default, your merchant account is configured so that all payments are captured automatically.

By enabling separate capture, every payment made using this merchant account will result in an authorisation. You are responsible for ensuring that these authorisations are captured.

To enable a separate manual capture:

  1. Log in to your Customer Area, and select the merchant account you want to configure.
  2. Navigate to Account > Settings
  3. In the Capture Delay drop-down, select manual.

    This will enable manual capture for your online and in-app payments.

  4. In the POS Capture Delay drop-down, select manual.

    This will enable manual capture for your point of sale payments.

  5. Click Submit to save your settings.

Now that your merchant account is configured for separate manual captures, you are ready to start sending payment authorisations.

Step 1: Authorise payment

After enabling manual capture, you can authorise a payment on a customer's card by making a payment request.

Authorisations expire after seven days. If an authorisation is not captured by this time you will be unable to transfer the funds to your account.

Select the platform that you are authorising a payment on.

Make a POST /payments request. In our example, we make a card payment for 5.00 EUR.

Payments request
{
    "amount": {
    "currency": "EUR",
    "value": 500
    },
    "reference": "YOUR_ORDER_NUMBER",
    "paymentMethod": {
        "type": "scheme",
        "encryptedCardNumber": "test_4111111111111111",
        "encryptedExpiryMonth": "test_03",
        "encryptedExpiryYear": "test_2030",
        "encryptedSecurityCode": "test_737"
    },
    "returnUrl": "https://your-company.com/...",
    "merchantAccount": "YOUR_MERCHANT_ACCOUNT"
}

The response includes:

  • pspReference: Our unique identifier for this payment request. You will use this PSP reference to capture the payment.

The following example shows a successful response with a PSP reference of 881468919096134D.

{
    "pspReference": "881468919096134D",
    "resultCode": "Authorised"
}

Make a POST request to a Terminal API endpoint. In our example, we make a card payment for 5.00 EUR.

Terminal API request
{
    "SaleToPOIRequest":{
        "MessageHeader":{
            "ProtocolVersion":"3.0",
            "MessageClass":"Service",
            "MessageCategory":"Payment",
            "MessageType":"Request",
            "SaleID":"POSSystemID12345",
            "ServiceID":"0207111104",
            "POIID":"V400m-324688179"
        },
        "PaymentRequest":{
            "SaleData":{
                "SaleTransactionID":{
                    "TransactionID":"YOUR_ORDER_NUMBER",
                    "TimeStamp":"2020-03-07T10:11:04+00:00"
                }
            },
            "PaymentTransaction":{
                "AmountsReq":{
                    "Currency":"EUR",
                    "RequestedAmount":5.00
                }
            }
        }
    }
}

The response includes:

  • pspReference: Our unique identifier for this payment request. You will use this PSP reference to capture the payment.

The following example shows a response with a PSP reference of 881468919096134D.

Payment response
{
    "SaleToPOIResponse":{
        "MessageHeader":{...},
        "PaymentResponse":{
            "POIData":{
                "POITransactionID":{
                    "TransactionID": "oLkO0012498220087123.881468919096134D"
                },
                ...
            },
            "Response":{
                "Result": "Success",
                ...
            },
            ...
        },
        "PaymentReceipt":{...}
    }
}

Step 2: Capture payment

When the order has been fulfilled, make a capture request. When you are fulfilling the whole order, you should capture the full amount of the authorisation. If you are only fulfilling part of the customer's order (for example, you only dispatched some of the order items), you should capture only the amount you are dispatching (this is called a partial capture).

To capture a payment:

  1. Make a POST /capture request, specifying:

    • modificationAmount: Object that contains the value and currency you are capturing. The value can be the full value of the transaction or less (a partial capture) and the currency must match the currency used in authorisation.
    • originalReference: The PSP reference of the payment request being captured.

    The example below shows how you would capture the authorisation with the PSP reference of 881468919096134D.

    Capture request
    {
        "merchantAccount":"YOUR_MERCHANT_ACCOUNT",
        "modificationAmount":{
            "value":500,
            "currency":"EUR"
        },
        "originalReference":"881468919096134D",
        "reference":"YOUR_CAPTURE_REFERENCE"
    }

    You receive a /capture response containing:

    • pspReference: Our unique identifier for this capture request. Save this, as you'll use this identifier to check if the request has been successful.
    • response: [capture-received] Confirmation that the capture request has been received. You receive the result of the request in a notification webhook.

    The example below indicates that the request was received, and the PSP reference for this capture request is 882540819540950H.

    Capture response
    {
        "pspReference":"882540819540950H",
        "response":"[capture-received]"
    }
  2. Wait for the notification webhook to confirm whether the request was successful. The notification webhook contains:

    • pspReference: The pspReference of the capture request, matching the pspReference you received in the /capture response.
    • eventCode: Depending on the result, you receive either CAPTURE or CAPTURE_FAILED. In case of an unsuccessful capture, refer to Failed capture documentation.

    The example below shows what a notification looks like for a successful capture request with the PSP reference 882540819540950H.

    CAPTURE notification webhook
    {
        "live":"false",
        "notificationItems":[
            {
                "NotificationRequestItem":{
                    "amount":{
                        "currency":"EUR",
                        "value":500
                    },
                    "eventCode":"CAPTURE",
                    "eventDate":"2020-03-08T10:11:04+00:00",
                    "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT",
                    "originalReference":"881468919096134D",
                    "pspReference":"882540819540950H",
                    "reason":"",
                    "success":"true"
                }
            }
        ]
    }

For more information on capturing authorisation, see our Capture documentation.

Optional: Cancelling an authorisation

If your customer cancels their order, or you are unable to fulfill it, you can cancel an authorisation. This removes the hold you placed on the customer's card. To cancel an authorisation:

  1. Make a /cancel request, specifying:

    • originalReference: The pspReference of the payment request being cancelled.

    The example below shows how you would cancel an authorisation with the PSP reference of 881468919096134D:

    Cancel request
    {
        "merchantAccount" : "YOUR_MERCHANT_ACCOUNT",
        "originalReference" : "881468919096134D",
        "reference" : "YOUR_MODIFICATION_REFERENCE"
    }

    You receive a response containing: 

    • pspReference: Our unique identifier for this cancel request. Save this, as you'll use this identifier to check if the request has been successful.
    • response: [cancel-received] Confirmation that the cancel request has been received. You receive the result of the cancel request in a notification webhook.

    The example below indicates that the request was received, and the PSP reference for this cancel request is 8412534564722331.

    /cancel response
    {
        "pspReference" : "8412534564722331",
        "response" : "[cancel-received]"
    }
  2. Wait for a notification webhook to confirm if the request was successful. The notification webhook contains:

    • pspReference: The pspReference of the cancel request, matching the pspReference you received in the /cancel response.
    • eventCode: CANCELLATION
    • success: Indicates true if the cancel request was successful. If false, check the reason field to know why the request failed. Fix the issue if possible, and resubmit the cancel request.
    CANCELLATION notification webhook
    {
      "live":"false",
      "notificationItems":[
         {
            "NotificationRequestItem":{
               "amount":{
                  "currency":"EUR",
                  "value":500
               },
               "eventCode":"CANCELLATION",
               "eventDate":"2018-03-05T09:08:05+01:00",
               "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT",
               "originalReference":"8313547924770610",
               "paymentMethod":"mc",
               "pspReference":"8412534564722331",
               "reason":"",
               "success":"true"
            }
         }
      ]
    }

For more information on cancelling authorisations, see our Cancel documentation.

Cross-channel returns

Cross-channel returns lets your customers return a purchase in the way most convenient for them. For example, they can return an online purchase to a physical store, or return their in-store purchase by sending it to your distribution center.

By default, refunds must be processed on the same merchant account where the original payment was made.

If you want to process cross-channel returns between multiple merchant accounts, contact our Support Team to enable refunds on the company level. This will allow you to use the /refund endpoint to submit returns for any merchant account under your company account.

To refund a payment:

  1. Make a POST /refund request, specifying:

    • modificationAmount: The value and currency of the refund. The value can be the full value of the transaction or less (a partial refund), and the currency must match the currency used in authorisation.
    • originalReference: The PSP reference of the payment being refunded.

    The example below shows how you would refund a payment with the PSP reference 881468919096134D.

    Refund request
    {
        "merchantAccount" : "YOUR_MERCHANT_ACCOUNT",
        "modificationAmount" : {
            "value" : 500,
            "currency" : "EUR"
        },
        "originalReference" : "881468919096134D"
    }

    You receive a response containing:

    • pspReference: Our unique identifier for this refund request. Save this, as you'll use this identifier to check if the request has been successful.
    • response: [refund-received] Confirmation that the refund request has been received. You receive the result of the request in a notification webhook.

    The example below indicates that the refund request was received. The PSP reference for this refund request is 891253456472233H.

    Refund response
    {
        "pspReference" : "891253456472233H",
        "response" : "[refund-received]"
    }

    When you use the /refund API to refund an in-store payment, the customer does not need to swipe their card on the terminal. The payment is refunded directly to the payment method that they used to pay for the goods or services. This type of refund is called a referenced refund in a Point-of-sale integration.

  2. Wait for a notification webhook to confirm whether the request was successful. The notification includes:

    • pspReference: The pspReference of the refund request, matching the pspReference you received in the /refund response.
    • eventCode: REFUND

    The example below shows what a notification looks like for a refund request with the PSP reference 891253456472233H.

    Refund notification webhook
    {
       "live":"false",
       "notificationItems":[
          {
             "NotificationRequestItem":{
                "amount":{
                   "currency":"EUR",
                   "value":500
                },
                "eventCode":"REFUND",
                "originalReference":"881468919096134D",
                "pspReference":"891253456472233H",
                "success":"true",
                ...
             }
          }
       ]
    }

For more information on how you can issue refunds, see our Refund documentation.

Endless aisle

An endless aisle is a kiosk that your customers can use to browse and buy items from your full product inventory while they are in-store. In addition to offering a larger product range in your physical stores, an endless aisle can prevent lost sales when you do not have an item in stock.

Step 1: Set up a kiosk

Building your endless aisle

You can set up endless aisle with your own Terminal API integration, or use a plugin.

If you're already using an Adyen plugin for your online store, check if it supports Terminal API. For example, Magento 2 and NetSuite supports Terminal API out of the box.

To build an endless aisle, you will need to install a kiosk in your physical store. This kiosk should contain:

  • A touch-screen tablet or computer. Your customers will use the device to sign in to, or register for, an account. They will also use it to browse your product range, and select products. When the customer is ready pay for their purchase, your device must be able to make a POST request to the Terminal API.
  • An Adyen point-of-sale terminal. Instead of the customer providing their payment details as they would when paying in your online store, they use the terminal to make the payment. This makes the payment process faster and more secure.

(Optional) Step 2: Recognize shopper

After your customer selects products, you can optionally prompt them to:

Alternatively, the customer could use your guest checkout.

Step 3: Initiate payment

Since the payment is for an out-of-stock item, consider only capturing the payment once goods have been shipped to the customer. Refer to Capture on fulfillment.

When a customer is ready to pay, the cash register software in your kiosk should initiate a point-of-sale payment request:

  1. Make a POST request to a Terminal API endpoint. If you prompted a new customer to register for an account in step 2, also include other parameters provided in the Create customer profiles documentation.

    The example below shows how you would make a 10.99 EUR payment request.

    Terminal API request
    {
      "SaleToPOIRequest":{
        "MessageHeader":{
          "ProtocolVersion":"3.0",
          "MessageClass":"Service",
          "MessageCategory":"Payment",
          "MessageType":"Request",
          "SaleID":"POSSystemID12345",
          "ServiceID":"0207111104",
          "POIID":"V400m-324688179"
        },
        "PaymentRequest":{
          "SaleData":{
            "SaleTransactionID":{
              "TransactionID":"27908",
              "TimeStamp":"2019-03-07T10:11:04+00:00"
            }
          },
          "PaymentTransaction":{
            "AmountsReq":{
              "Currency":"EUR",
              "RequestedAmount":10.99
            }
          }
        }
      }
    }

    If the request has been successful, you receive a response containing:

    • POIData.POITransactionID.TransactionID: Transaction identifier for the payment.
    • PaymentResponse.Response.Result: Success

    The example result below indicates that the payment was successful. The transaction identifier for this payment is oLkO0012498220087000.981517998282382C.

    Payment response
    {
      "SaleToPOIResponse":{
        "MessageHeader":{...},
        "PaymentResponse":{
          "POIData":{
            "POITransactionID":{
              "TransactionID": "oLkO0012498220087000.981517998282382C"
            },
            ...
          },
          "Response":{
            "Result":"Success"
          },
          ...
        },
        "PaymentReceipt":{...}
      }
    }
  2. If the transaction was successful, present a message on the kiosk to inform the customer.

Next steps