Adyen
Accept payments with Adyen
Adyen Payment Provider
Table of Contents
- Introduction
- Installation and Setup
- Install the Package
- Configure the Plugin
- Plugin Options
- Required Options
- Optional Options
- Webhooks
- Asynchronous Payment Operations
- How the Plugin Handles This
- Important Considerations
- Asynchronous Payment Operations
- PCI Compliance Considerations
- Development
- Integration Tests
- Example Storefront
- Known Issues
Introduction
This plugin implements a Medusa payment provider for Adyen, delivering backend (payment server) integration for Adyen's Advanced flow. It handles server-side payment operations such as payment session creation, authorization, capture, refunds, and webhook processing.
The plugin is frontend-agnostic and compatible with any Advanced flow frontend implementation supported by Adyen, including Web Components, Drop-in, and custom integrations. A dedicated section with frontend code examples is provided below.
⚠️ Production Readiness: This plugin is not currently considered safe or ready for production use. Fundamental differences between Medusa's payment module design, which assumes synchronous payment operations, and Adyen's asynchronous payment protocol introduce challenges in maintaining accurate payment state synchronization. Additionally, the integration requires storing sensitive payment data on the Medusa server, which may pose PCI compliance risks. These issues are explained in more detail in the Webhooks and PCI Compliance Considerations sections.
⚠️ Version Compatibility: Due to its webhook workflow implementation, this plugin is brittle and tightly coupled to a specific Medusa version. There is no guarantee it will function correctly with other Medusa versions, as it relies on internal payment module methods to manipulate payment models. These methods and underlying models may change between Medusa releases, potentially breaking the plugin.
Installation and Setup
Install the Package
Install the plugin beta using npm (recommended for early adopters):
1npm install @minimall.io/medusa-plugin-adyen@beta
Install a specific beta version (recommended for reproducible deployments):
1npm install @minimall.io/medusa-plugin-adyen@0.0.1-beta.0
Install the latest stable release (will be available once a stable version is published to the Copy to clipboardlatest tag):
1npm install @minimall.io/medusa-plugin-adyen
Configure the Plugin
Configure the Medusa Payment Module Options with the Adyen payment provider in your Medusa instance by updating the Copy to clipboardmedusa-config.ts file:
1234567891011121314151617181920import { defineConfig } from '@medusajs/framework/utils'export default defineConfig({// ... other configurationsplugins: [{resolve: '@minimall.io/medusa-plugin-adyen',options: {},},],modules: [{resolve: '@medusajs/medusa/payment',options: {providers: [{resolve: '@minimall.io/medusa-plugin-adyen/providers/adyen',id: 'adyen', // Your provider IDoptions: {apiKey: process.env.ADYEN_API_KEY,
Plugin Options
The following options are available for configuring the Adyen payment provider.
Required Options
- Copy to clipboard
apiKey(string): Your Adyen API key, used to authenticate API requests. See the Adyen documentation. - Copy to clipboard
hmacKey(string): HMAC key used to validate webhook notifications. Required for secure webhook processing. See the Adyen documentation. - Copy to clipboard
merchantAccount(string): Your Adyen merchant account identifier. See the Adyen documentation. - Copy to clipboard
liveEndpointUrlPrefix(string): Your live endpoint URL prefix. Required when using the live environment. See the Adyen documentation.
Optional Options
- Copy to clipboard
environment(string): The Adyen environment to use. Defaults to Copy to clipboardTEST. Set to Copy to clipboardLIVEfor production. This must match the environment of your API credentials. - Copy to clipboard
shopperInteraction(string): Shopper interaction type for payments. Refer to the Adyen documentation for available values and token creation. - Copy to clipboard
recurringProcessingModel(string): Recurring processing model for stored payment methods. Refer to the Adyen documentation for available values and token creation. - Copy to clipboard
apiInitialRetryDelay(number): Initial delay, in milliseconds, before retrying failed API requests. Defaults to Copy to clipboard1000(1 second). - Copy to clipboard
apiMaxRetries(number): Maximum number of retry attempts for failed API requests. Defaults to Copy to clipboard3.
Note: Provider-level Copy to clipboardshopperInteraction and Copy to clipboardrecurringProcessingModel options override values specified in individual payment requests. If these options are not set at the provider level, the values from the payment request will be used.
Webhooks
Webhooks are a critical component of the Adyen payment provider integration. While the Medusa payment module assumes payment operations return definitive results synchronously, Adyen operates using an asynchronous model.
Asynchronous Payment Operations
When merchant infrastructure (a Medusa server) sends a payment operation API request to Adyen—such as authorization, cancellation, capture, or refund—Adyen typically responds only with an acknowledgement of receipt. It does not immediately indicate whether the operation succeeded or failed. The final outcome is delivered later via a webhook notification from Adyen to the Medusa server.
How the Plugin Handles This
To accommodate Medusa's synchronous assumptions, the plugin implements the following approach:
- Treats request acknowledgements as initial success states: When the Adyen API acknowledges a payment operation request with the response Copy to clipboard
statusfield set to Copy to clipboardreceived, the plugin updates the payment (Copy to clipboardPayment) Copy to clipboarddatafield to reflect the current response state and returns it, along with other relevant information, to the Medusa Payment Module to indicate a successful operation. - Finalizes payment state via webhooks: When the corresponding webhook is received, the plugin's Adyen webhook workflow processes the notification and updates the final state of the relevant Medusa entities, including payment collections, payment sessions, payments, captures, refunds, and related records.
This approach helps keep Medusa's payment records synchronized with Adyen's actual payment states.
Important Considerations
Operations may initially appear successful but ultimately fail. A payment operation that is initially recorded as successful may later fail when the webhook notification is processed.
Currently, the plugin does not provide a notification mechanism to alert merchants when webhooks are received. As a result, the transaction's state must be determined by manually inspecting the payment Copy to clipboarddata field in the order's JSON structure (Copy to clipboardpayment_collections[i].payments[j].data.events[k].status). The Copy to clipboardstatus field can have one of the following values: Copy to clipboardREQUESTED, Copy to clipboardFAILED, or Copy to clipboardSUCCEEDED. A Copy to clipboardstatus value of Copy to clipboardREQUESTED indicates that the operation request has been received by Adyen and corresponds to Adyen's response Copy to clipboardstatus value of Copy to clipboardreceived; however, the corresponding webhook has not yet been received. Merchants should rely on webhook-confirmed payment states when processing orders and must avoid taking irreversible actions until webhook notifications confirm that payment operations have completed successfully. While the plugin automatically synchronizes payment states, merchant business logic should explicitly wait for webhook confirmation before proceeding.
PCI Compliance Considerations
Adyen's Advanced flow expects the Copy to clipboard/payments Checkout API request (the payment authorization), which carries sensitive payment data, to originate from merchant infrastructure (a Medusa server). To ensure security, Adyen provides frontend-side encryption of sensitive payment data, which can be used when making the request.
However, Medusa's payment module Copy to clipboardauthorizePaymentSession method, which initiates payment authorization, does not accept frontend-provided Copy to clipboarddata value at the time of invocation. Instead, it retrieves and forwards the Copy to clipboarddata value already stored in the associated payment session (Copy to clipboardPaymentSession). This requires sensitive payment data to be present in the session's Copy to clipboarddata field prior to authorization.
Consequently, sensitive payment data must be transmitted from the frontend and stored on the Medusa server before authorization is initiated, through Medusa Payment Module APIs (for example, Copy to clipboardupdatePayment). This results in sensitive payment data persisting on the Medusa server, which may introduce PCI compliance risks.
To minimize the retention period of sensitive data, the plugin reacts upon receiving the first related webhook notification by overwriting the payment session Copy to clipboarddata field with values drawn from the corresponding payment (Copy to clipboardPayment) Copy to clipboarddata field, which do not contain payment details.
To improve the chances of PCI compliance clearance, it is highly advised to leverage Adyen's frontend encryption for sensitive payment data fields.
Development
Integration Tests
Integration tests depend on the following environment variables:
- Copy to clipboard
ADYEN_PROVIDER_ID(required): Represents the Copy to clipboardidportion of the payment provider's unique identifier (Copy to clipboardpp_{identifier}_{id}). Payment module service calls used by the integration tests rely on this value. It must match the value defined in Copy to clipboardconfig.modules[i].options.providers[j].idwithin the Copy to clipboardmedusa-config.tsfile. - Copy to clipboard
ADYEN_API_LIVE_TESTS(optional): A boolean flag that determines whether integration tests use live Adyen API endpoints. Set to Copy to clipboard'true'to use live endpoints, or Copy to clipboard'false'(or leave undefined) to use mocked responses. Using mocks is recommended for consistent and reliable testing.
Example Storefront
The Copy to clipboardexamples folder contains a Medusa storefront with Adyen integration. This example is based on the Medusa Next.js Starter Storefront and is not intended for production use. However, it can be useful for manual end-to-end testing of the plugin and as a reference for integrating Adyen payments into Medusa storefronts.
Known Issues
The Copy to clipboardBUGS.md file documents issues with Medusa that were encountered during plugin development. These include problems with the payment module's design, method implementations, and integration test infrastructure. The file also contains recommended fixes and workarounds for some of these issues.

