Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ The library supports all webhooks under the following model directories:
| [Management Webhooks](https://docs.adyen.com/api-explorer/ManagementNotification/3/overview) | Adyen uses webhooks to inform your system about events that happen with your Adyen company and merchant accounts, stores, payment terminals, and payment methods when using Management API. | [ManagementWebhooks](src/typings/managementWebhooks) | **v3** |
| [Notification Webhooks](https://docs.adyen.com/api-explorer/Webhooks/1/overview) | We use webhooks to send you updates about payment status updates, newly available reports, and other events that you can subscribe to. For more information, refer to our documentation | [Notification](src/typings/notification) | **v1** |
| [Transaction Webhooks](https://docs.adyen.com/api-explorer/transaction-webhooks/4/overview) | Adyen sends webhooks to inform your system about incoming and outgoing transfers in your platform. You can use these webhooks to build your implementation. For example, you can use this information to update balances in your own dashboards or to keep track of incoming funds. | [TransactionWebhooks](src/typings/transactionWebhooks) | **v4** |
| [Tokenization Webhooks](https://docs.adyen.com/api-explorer/Tokenization-webhooks/1/overview) | Adyen sends webhooks to inform you about the creation and changes to the recurring tokens. | [tokenizationwebhooks](src/main/java/com/adyen/model/tokenizationwebhooks) | **v1** |

For more information, refer to our [documentation](https://docs.adyen.com/) or the [API Explorer](https://docs.adyen.com/api-explorer/).

Expand Down
119 changes: 119 additions & 0 deletions src/__tests__/webhooks/tokenizationWebhooks.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { TokenizationAlreadyExistingDetailsNotificationRequest } from "../../typings/tokenizationWebhooks/tokenizationAlreadyExistingDetailsNotificationRequest";
import { TokenizationCreatedDetailsNotificationRequest } from "../../typings/tokenizationWebhooks/tokenizationCreatedDetailsNotificationRequest";
import { TokenizationDisabledDetailsNotificationRequest } from "../../typings/tokenizationWebhooks/tokenizationDisabledDetailsNotificationRequest";
import { TokenizationUpdatedDetailsNotificationRequest } from "../../typings/tokenizationWebhooks/tokenizationUpdatedDetailsNotificationRequest";
import { TokenizationWebhooksHandler } from "../../typings/tokenizationWebhooks/tokenizationWebhooksHandler";

describe("TokenizationWebhooksHandler", () => {
it("should deserialize TokenizationAlreadyExistingDetailsNotificationRequest", () => {
const json = {
"createdAt": "2025-06-30T16:40:23+02:00",
"eventId": "QBQQ9DLNRHHKGK38",
"environment": "test",
"data": {
"merchantAccount": "YOUR_MERCHANT_ACCOUNT",
"storedPaymentMethodId": "M5N7TQ4TG5PFWR50",
"type": "visastandarddebit",
"operation": "alreadyExisting",
"shopperReference": "YOUR_SHOPPER_REFERENCE"
},
"type": "recurring.token.alreadyExisting"
};
const handler = new TokenizationWebhooksHandler(JSON.stringify(json));
const request = handler.getTokenizationAlreadyExistingDetailsNotificationRequest();
expect(request).toBeTruthy();
expect(request.type).toBe(TokenizationAlreadyExistingDetailsNotificationRequest.TypeEnum.RecurringTokenAlreadyExisting);
expect(request.data.type).toBe("visastandarddebit");
// test GenericWebhook
const genericWebhook = handler.getGenericWebhook();
expect(genericWebhook).toBeInstanceOf(TokenizationAlreadyExistingDetailsNotificationRequest);
expect(genericWebhook.type).toBe("recurring.token.alreadyExisting");
});

it("should deserialize TokenizationCreatedDetailsNotificationRequest", () => {
const json = {
"createdAt": "2025-06-30T16:40:23+02:00",
"eventId": "QBQQ9DLNRHHKGK38",
"environment": "test",
"data": {
"merchantAccount": "YOUR_MERCHANT_ACCOUNT",
"storedPaymentMethodId": "M5N7TQ4TG5PFWR50",
"type": "visastandarddebit",
"operation": "created",
"shopperReference": "YOUR_SHOPPER_REFERENCE"
},
"type": "recurring.token.created"
};
const handler = new TokenizationWebhooksHandler(JSON.stringify(json));
const request = handler.getTokenizationCreatedDetailsNotificationRequest();
expect(request).toBeTruthy();
expect(request.type).toBe(TokenizationCreatedDetailsNotificationRequest.TypeEnum.RecurringTokenCreated);
expect(request.data.type).toBe("visastandarddebit");
// test GenericWebhook
const genericWebhook = handler.getGenericWebhook();
expect(genericWebhook).toBeInstanceOf(TokenizationCreatedDetailsNotificationRequest);
expect(genericWebhook.type).toBe("recurring.token.created");
});

it("should deserialize TokenizationUpdatedDetailsNotificationRequest", () => {
const json = {
"createdAt": "2025-06-30T16:40:23+02:00",
"eventId": "QBQQ9DLNRHHKGK38",
"environment": "test",
"data": {
"merchantAccount": "YOUR_MERCHANT_ACCOUNT",
"storedPaymentMethodId": "M5N7TQ4TG5PFWR50",
"type": "visastandarddebit",
"operation": "updated",
"shopperReference": "YOUR_SHOPPER_REFERENCE"
},
"type": "recurring.token.updated"
};
const handler = new TokenizationWebhooksHandler(JSON.stringify(json));
const request = handler.getTokenizationUpdatedDetailsNotificationRequest();
expect(request).toBeTruthy();
expect(request.type).toBe(TokenizationUpdatedDetailsNotificationRequest.TypeEnum.RecurringTokenUpdated);
expect(request.data.type).toBe("visastandarddebit");
// test GenericWebhook
const genericWebhook = handler.getGenericWebhook();
expect(genericWebhook).toBeInstanceOf(TokenizationUpdatedDetailsNotificationRequest);
expect(genericWebhook.type).toBe("recurring.token.updated");
});

it("should deserialize TokenizationDisabledDetailsNotificationRequest", () => {
const json = {
"createdAt": "2025-06-30T16:40:23+02:00",
"eventId": "QBQQ9DLNRHHKGK38",
"environment": "test",
"data": {
"merchantAccount": "YOUR_MERCHANT_ACCOUNT",
"storedPaymentMethodId": "M5N7TQ4TG5PFWR50",
"type": "visastandarddebit",
"shopperReference": "YOUR_SHOPPER_REFERENCE"
},
"type": "recurring.token.disabled"
};
const handler = new TokenizationWebhooksHandler(JSON.stringify(json));
const request = handler.getTokenizationDisabledDetailsNotificationRequest();
expect(request).toBeTruthy();
expect(request.type).toBe(TokenizationDisabledDetailsNotificationRequest.TypeEnum.RecurringTokenDisabled);
expect(request.data.type).toBe("visastandarddebit");
// test GenericWebhook
const genericWebhook = handler.getGenericWebhook();
expect(genericWebhook).toBeInstanceOf(TokenizationDisabledDetailsNotificationRequest);
expect(genericWebhook.type).toBe("recurring.token.disabled");
});

it("should throw error for unknown type", () => {
const json = {
type: "unknown.type",
data: {}
};
const handler = new TokenizationWebhooksHandler(JSON.stringify(json));
expect(() => handler.getGenericWebhook()).toThrow("Could not parse the json payload");
});

it("should throw SyntaxError for invalid JSON", () => {
expect(() => new TokenizationWebhooksHandler("{ invalid json }")).toThrow(SyntaxError);
});
});
2 changes: 1 addition & 1 deletion src/typings/checkout/authenticationData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class AuthenticationData {
*/
"attemptAuthentication"?: AuthenticationData.AttemptAuthenticationEnum;
/**
* If set to true, you will only perform the [3D Secure 2 authentication](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only), and not the payment authorisation. Default: **false**.
* Required to trigger the [authentication-only flow](https://docs.adyen.com/online-payments/3d-secure/authentication-only/). If set to **true**, you will only perform the 3D Secure 2 authentication, and will not proceed to the payment authorization. Default: **false**.
*/
"authenticationOnly"?: boolean;
"threeDSRequestData"?: ThreeDSRequestData | null;
Expand Down
8 changes: 4 additions & 4 deletions src/typings/checkout/balanceCheckRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ export class BalanceCheckRequest {
*/
"sessionId"?: string;
/**
* The shopper\'s email address. We recommend that you provide this data, as it is used in velocity fraud checks. > For 3D Secure 2 transactions, schemes require `shopperEmail` for all browser-based and mobile implementations.
* The shopper\'s email address. We recommend that you provide this data, as it is used in velocity fraud checks. > Required for Visa and JCB transactions that require 3D Secure 2 authentication if you did not include the `telephoneNumber`.
*/
"shopperEmail"?: string;
/**
* The shopper\'s IP address. In general, we recommend that you provide this data, as it is used in a number of risk checks (for instance, number of payment attempts or location-based checks). > For 3D Secure 2 transactions, schemes require `shopperIP` for all browser-based implementations. This field is also mandatory for some merchants depending on your business model. For more information, [contact Support](https://www.adyen.help/hc/en-us/requests/new).
* The shopper\'s IP address. We recommend that you provide this data, as it is used in a number of risk checks (for instance, number of payment attempts or location-based checks).> Required for Visa and JCB transactions that require 3D Secure 2 authentication for all web and mobile integrations, if you did not include the `shopperEmail`. For native mobile integrations, the field is required to support cases where authentication is routed to the redirect flow. This field is also mandatory for some merchants depending on your business model. For more information, [contact Support](https://www.adyen.help/hc/en-us/requests/new).
*/
"shopperIP"?: string;
/**
Expand Down Expand Up @@ -143,12 +143,12 @@ export class BalanceCheckRequest {
*/
"store"?: string;
/**
* The shopper\'s telephone number.
* The shopper\'s telephone number. > Required for Visa and JCB transactions that require 3D Secure 2 authentication, if you did not include the `shopperEmail`. The phone number must include a plus sign (+) and a country code (1-3 digits), followed by the number (4-15 digits). If the value you provide does not follow the guidelines, we drop the value and do not submit it for authentication.
*/
"telephoneNumber"?: string;
"threeDS2RequestData"?: ThreeDS2RequestData | null;
/**
* If set to true, you will only perform the [3D Secure 2 authentication](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only), and not the payment authorisation.
* Required to trigger the [authentication-only flow](https://docs.adyen.com/online-payments/3d-secure/authentication-only/). If set to **true**, you will only perform the 3D Secure 2 authentication, and will not proceed to the payment authorization.Default: **false**.
*
* @deprecated since Adyen Checkout API v69
* Use `authenticationData.authenticationOnly` instead.
Expand Down
8 changes: 4 additions & 4 deletions src/typings/checkout/createCheckoutSessionRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export class CreateCheckoutSessionRequest {
*/
"reference": string;
/**
* The URL to return to in case of a redirection. The format depends on the channel. * For web, include the protocol `http://` or `https://`. You can also include your own additional query parameters, for example, shopper ID or order reference number. Example: `https://your-company.com/checkout?shopperOrder=12xy` * For iOS, use the custom URL for your app. To know more about setting custom URL schemes, refer to the [Apple Developer documentation](https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app). Example: `my-app://` * For Android, use a custom URL handled by an Activity on your app. You can configure it with an [intent filter](https://developer.android.com/guide/components/intents-filters). Example: `my-app://your.package.name` If the URL to return to includes non-ASCII characters, like spaces or special letters, URL encode the value. > The URL must not include personally identifiable information (PII), for example name or email address.
* The URL to return to in case of a redirection. The format depends on the channel. * For web, include the protocol `http://` or `https://`. You can also include your own additional query parameters, for example, shopper ID or order reference number. Example: `https://your-company.com/checkout?shopperOrder=12xy` * For iOS, use the custom URL for your app. To know more about setting custom URL schemes, refer to the [Apple Developer documentation](https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app). Example: `my-app://` * For Android, use a custom URL handled by an Activity on your app. You can configure it with an [intent filter](https://developer.android.com/guide/components/intents-filters). Example: `my-app://your.package.name` If the URL to return to includes non-ASCII characters, like spaces or special letters, URL encode the value. We strongly recommend that you use a maximum of 1024 characters. > The URL must not include personally identifiable information (PII), for example name or email address.
*/
"returnUrl": string;
"riskData"?: RiskData | null;
Expand All @@ -151,7 +151,7 @@ export class CreateCheckoutSessionRequest {
*/
"shopperEmail"?: string;
/**
* The shopper\'s IP address. In general, we recommend that you provide this data, as it is used in a number of risk checks (for instance, number of payment attempts or location-based checks). > For 3D Secure 2 transactions, schemes require `shopperIP` for all browser-based implementations. This field is also mandatory for some merchants depending on your business model. For more information, [contact Support](https://www.adyen.help/hc/en-us/requests/new).
* The shopper\'s IP address. We recommend that you provide this data, as it is used in a number of risk checks (for instance, number of payment attempts or location-based checks).> Required for Visa and JCB transactions that require 3D Secure 2 authentication for all web and mobile integrations, if you did not include the `shopperEmail`. For native mobile integrations, the field is required to support cases where authentication is routed to the redirect flow. This field is also mandatory for some merchants depending on your business model. For more information, [contact Support](https://www.adyen.help/hc/en-us/requests/new).
*/
"shopperIP"?: string;
/**
Expand Down Expand Up @@ -208,7 +208,7 @@ export class CreateCheckoutSessionRequest {
*/
"storePaymentMethodMode"?: CreateCheckoutSessionRequest.StorePaymentMethodModeEnum;
/**
* The shopper\'s telephone number.
* The shopper\'s telephone number. > Required for Visa and JCB transactions that require 3D Secure 2 authentication, if you did not include the `shopperEmail`. The phone number must include a plus sign (+) and a country code (1-3 digits), followed by the number (4-15 digits). If the value you provide does not follow the guidelines, we drop the value and do not submit it for authentication.
*/
"telephoneNumber"?: string;
/**
Expand All @@ -217,7 +217,7 @@ export class CreateCheckoutSessionRequest {
"themeId"?: string;
"threeDS2RequestData"?: CheckoutSessionThreeDS2RequestData | null;
/**
* If set to true, you will only perform the [3D Secure 2 authentication](https://docs.adyen.com/online-payments/3d-secure/other-3ds-flows/authentication-only), and not the payment authorisation.
* Required to trigger the [authentication-only flow](https://docs.adyen.com/online-payments/3d-secure/authentication-only/). If set to **true**, you will only perform the 3D Secure 2 authentication, and will not proceed to the payment authorization.Default: **false**.
*
* @deprecated since Adyen Checkout API v69
* Use `authenticationData.authenticationOnly` instead.
Expand Down
Loading