Cloud device API
August 5, 2026 ยท View on GitHub
The Cloud device API is our solution to create best-in-class in-person payments integrations.
With the Cloud device API you can:
- send Terminal API requests to a cloud endpoint. You can use this communication method when it is not an option to send Terminal API requests over your local network directly to a payment terminal.
- check the cloud connection of a payment terminal or of a device used in a Mobile solution for in-person payments.
Benefits of the Cloud device API
The Cloud device API offers the following benefits:
- access to API logs in the Customer Area for troubleshooting errors
- using a version strategy for the API endpoints for controlled and safer rollouts
- improved reliability and security (OAuth support)
New features and products will be released exclusively on the Cloud device API.
Use the Cloud device API
Setup
First you must initialize the Client (see an example on TEST):
// Import the required classes
import { Client, Config, EnvironmentEnum, CloudDeviceAPI } from "@adyen/api-library";
import {
MessageCategory,
MessageClass,
MessageType,
SaleToPOIRequest,
} from "@adyen/api-library/lib/src/typings/tapi/models";
import { CloudDeviceApiRequest } from "@adyen/api-library/lib/src/typings/clouddevice/models";
// Setup Client on TEST
const client = new Client(new Config({ apiKey: "YOUR_API_KEY", environment: EnvironmentEnum.TEST }));
const cloudDeviceAPI = new CloudDeviceAPI(client);
On the LIVE environment you must set the closest Region:
import { Client, Config, EnvironmentEnum, RegionEnum, CloudDeviceAPI } from "@adyen/api-library";
// Setup Client on LIVE (Region is required)
const client = new Client(new Config({
apiKey: "YOUR_API_KEY",
environment: EnvironmentEnum.LIVE,
region: RegionEnum.US, // set to the region closest to your terminals
}));
const cloudDeviceAPI = new CloudDeviceAPI(client);
Send a payment SYNC request
The sync and async endpoints require merchantAccount and deviceId as parameters, in addition to the request body. Make sure the POIID in the MessageHeader matches the deviceId.
const request: CloudDeviceApiRequest = {
SaleToPOIRequest: {
MessageHeader: {
ProtocolVersion: "3.0",
MessageClass: MessageClass.Service,
MessageCategory: MessageCategory.Payment,
MessageType: MessageType.Request,
SaleID: "001",
ServiceID: "001",
POIID: "P400Plus-123456789",
},
PaymentRequest: {
SaleData: {
SaleTransactionID: {
TransactionID: "001",
TimeStamp: new Date(),
},
},
PaymentTransaction: {
AmountsReq: {
Currency: "EUR",
RequestedAmount: 1,
},
},
},
},
};
const response = await cloudDeviceAPI.CloudDeviceApi.sync("myMerchant", "P400Plus-123456789", request);
console.log(response.SaleToPOIResponse);
Send a payment ASYNC request
If you choose to receive the response asynchronously, you only need to use a different method (async).
Don't forget to set up event notifications in the Customer Area to be able to receive the Cloud device API responses.
// define the request (same as per sync)
const response = await cloudDeviceAPI.CloudDeviceApi.async("myMerchant", "P400Plus-123456789", request);
if (response.Result === "ok") {
// success
} else {
// request failed: see details in the EventNotification object
const eventNotification = response.SaleToPOIRequest?.EventNotification;
console.log("EventToNotify:", eventNotification?.EventToNotify);
console.log("EventDetails:", eventNotification?.EventDetails);
}
Verify the status of the terminals
The Cloud device API allows your integration to check the status of the terminals.
// list of payment terminals or SDK mobile installation IDs
const connectedDevices = await cloudDeviceAPI.CloudDeviceApi.getConnectedDevices("myMerchant");
console.log(connectedDevices.uniqueDeviceIds);
// ["P400Plus-123456789", "AMS1-000168242800763"]
// optionally filter by store
const storeDevices = await cloudDeviceAPI.CloudDeviceApi.getConnectedDevices("myMerchant", "YOUR_STORE_ID");
// check the payment terminal or SDK mobile installation ID
const deviceStatus = await cloudDeviceAPI.CloudDeviceApi.getDeviceStatus("myMerchant", "AMS1-000168242800763");
console.log(deviceStatus.status);
// ONLINE
Protect cloud communication
The Adyen Node.js library supports encrypting request and response payloads, allowing you to secure communication between your integration and the cloud.
Provide the encryption credentials configured on the Terminal in your Customer Area, and use EncryptedCloudDeviceApi instead of CloudDeviceApi. For details on how to set up these credentials (AdyenCryptoVersion, KeyIdentifier, KeyVersion, and Passphrase) in the Customer Area, see Protect communications.
import { EncryptedCloudDeviceApi } from "@adyen/api-library/lib/src/services/clouddevice/encryptedCloudDeviceApi";
import { EncryptionCredentialDetails } from "@adyen/api-library/lib/src/security/clouddevice/encryptionCredentialDetails";
// Encryption credentials from the Terminal configuration on CA
const encryptionCredentialDetails: EncryptionCredentialDetails = {
adyenCryptoVersion: 1,
keyIdentifier: "CryptoKeyIdentifier12345",
keyVersion: 1,
passphrase: "p@ssw0rd123456",
};
// Use EncryptedCloudDeviceApi instead of CloudDeviceApi
const encryptedCloudDeviceApi = new EncryptedCloudDeviceApi(client, encryptionCredentialDetails);
const response = await encryptedCloudDeviceApi.sync("TestMerchantAccount", "V400m-123456789", request);
console.log(response);
In case of asynchronous integration, you can decrypt the payload of the event notifications using the decryptNotification() method.
// JSON with encrypted SaleToPOIResponse (for async responses) or SaleToPOIRequest (for event notifications)
const payload = "...";
const decryptedPayload = encryptedCloudDeviceApi.decryptNotification(payload);
console.log(decryptedPayload);
Helper classes
PredefinedContentHelper
When your integration receives a Display event notification, the terminal sends a DisplayRequest with an OutputContent that contains a PredefinedContent.ReferenceID. This field is a query-string that encodes the event type and transaction context.
PredefinedContentHelper parses the ReferenceID and exposes typed accessors so you don't have to hand-roll query-string parsing.
import { PredefinedContentHelper, DisplayNotificationEvent } from "@adyen/api-library";
// referenceId comes from DisplayRequest.OutputContent.PredefinedContent.ReferenceID
const referenceId = "TransactionID=oLkO001517998574000&TimeStamp=2018-02-07T10%3a16%3a14.000Z&event=PIN_ENTERED";
const helper = new PredefinedContentHelper(referenceId);
const event = helper.getEvent(); // DisplayNotificationEvent.PIN_ENTERED or null
if (event === DisplayNotificationEvent.PIN_ENTERED) {
console.log("Customer is entering PIN");
}
console.log(helper.getTransactionId()); // "oLkO001517998574000"
console.log(helper.getTimeStamp()); // "2018-02-07T10:16:14.000Z"
console.log(helper.toObject()); // { TransactionID: "...", TimeStamp: "...", event: "PIN_ENTERED" }
The DisplayNotificationEvent enum contains all supported event values, such as CARD_INSERTED, WAIT_FOR_PIN, PIN_ENTERED, TENDER_FINAL, and others.
Working with SaleToAcquirerData
SaleToAcquirerData is a field you add to the SaleData of your Cloud device API PaymentRequest to send extra information to the acquirer, such as shopper details, recurring/tokenization settings, tender options, and custom metadata. See Add information to a payment. On the wire it is a single string, encoded either as Base64 JSON or as form-encoded key-value pairs.
Use SaleToAcquirerDataParser.toBase64(...) to build and encode it into an outgoing request. Use SaleDataHelper / SaleToAcquirerDataParser.parse(...) to decode a SaleData.SaleToAcquirerData string you already hold (for example when inspecting, logging, or forwarding a request).
SaleDataHelper
The SaleData.SaleToAcquirerData field carries sale information intended for the acquirer, encoded either as Base64 JSON or as form-encoded key-value pairs. SaleDataHelper wraps a SaleData object, auto-detects the format, and decodes it into a typed SaleToAcquirerData object.
import { SaleDataHelper, Types } from "@adyen/api-library";
const saleData = new Types.tapi.SaleData();
saleData.SaleToAcquirerData = "shopperEmail=foo@bar.com¤cy=EUR&metadata.orderId=42";
// returns the parsed SaleToAcquirerData, or null if the field is absent or unparsable
const acquirerData = new SaleDataHelper(saleData).getSaleToAcquirerData();
console.log(acquirerData);
// {
// shopperEmail: "foo@bar.com",
// currency: "EUR",
// metadata: { orderId: "42" }
// }
SaleToAcquirerDataParser
Use SaleToAcquirerDataParser directly when you have the raw string, or when you want to build and encode a SaleToAcquirerData payload yourself. It exposes parse (auto-detects the format), the explicit fromBase64 / fromKeyValuePairs decoders, and the toJson / toBase64 serializers.
import { SaleToAcquirerDataParser, SaleToAcquirerData, RecurringProcessingModel } from "@adyen/api-library";
// Parse a raw value, auto-detecting Base64 JSON vs key-value pairs
const parsed = SaleToAcquirerDataParser.parse("shopperEmail=foo@bar.com&tenderOption=AskGratuity");
// Build a payload and encode it for SaleData.SaleToAcquirerData
const data: SaleToAcquirerData = {
merchantAccount: "TestMerchant",
currency: "EUR",
shopperReference: "shopper-123",
recurringProcessingModel: RecurringProcessingModel.CardOnFile,
metadata: { orderId: "42" },
additionalData: {
captureDelayHours: "4",
},
};
const encoded = SaleToAcquirerDataParser.toBase64(data); // Base64 string, ready to assign to SaleData.SaleToAcquirerData