> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gr4vy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Adyen - Bank

> Configure ACH, SEPA, and BACS via Adyen as payment methods in Gr4vy.

export const connector = {
  displayName: "Pay by Bank (ACH)",
  method: "bank",
  features: "bank_aggregators bank_details create_transaction deep_linking direct_capture partial_refunds payment_method_tokenization refunds requires_webhook_setup settlement_reporting verify_credentials",
  supportedCountries: "AT BE BG CY CZ DE DK EE ES FI FR GB GR HR HU IE IT LT LU LV MT NL PL PT RO SE SI SK US",
  supportedCurrencies: "EUR GBP USD"
};

export const ConnectorRegions = ({data, kind, name: nameOverride}) => {
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(false);
  const isCountries = kind === "countries";
  const raw = data && (isCountries ? data.supportedCountries : data.supportedCurrencies);
  const codes = typeof raw === "string" ? raw.split(/\s+/).filter(Boolean) : Array.isArray(raw) ? raw : [];
  const DISPLAY_NAME_OVERRIDES = {
    authorizenet: "Authorize.net",
    cardpointe: "Fiserv CardPointe",
    dlocal: "dLocal",
    shift4i4go: "Shift4 i4go",
    tokenex: "TokenEx"
  };
  const rawName = data && data.displayName || "";
  const name = nameOverride || DISPLAY_NAME_OVERRIDES[rawName.toLowerCase()] || rawName || "This connector";
  const verb = isCountries ? "supports transactions from buyers in" : "supports processing payments in";
  const noun = isCountries ? "countries" : "currencies";
  if (codes.length === 0) return null;
  let displayNames = null;
  try {
    displayNames = new Intl.DisplayNames(["en"], {
      type: isCountries ? "region" : "currency"
    });
  } catch (e) {
    displayNames = null;
  }
  const resolve = code => {
    if (!displayNames) return null;
    try {
      const resolved = displayNames.of(code);
      return resolved && resolved !== code ? resolved : null;
    } catch (e) {
      return null;
    }
  };
  const MAJOR_CURRENCIES = ["USD", "EUR", "GBP", "CAD", "AUD", "JPY", "CHF", "CNY", "SGD", "HKD", "NZD", "SEK", "NOK", "DKK", "MXN", "BRL", "INR"];
  const items = codes.map(code => ({
    code,
    label: resolve(code)
  }));
  if (isCountries) {
    items.sort((a, b) => (a.label || a.code).localeCompare(b.label || b.code));
  } else {
    const rank = code => {
      const i = MAJOR_CURRENCIES.indexOf(code);
      return i === -1 ? MAJOR_CURRENCIES.length : i;
    };
    items.sort((a, b) => rank(a.code) - rank(b.code) || a.code.localeCompare(b.code));
  }
  if (codes.length <= 3) {
    const parts = items.map(it => isCountries || !it.label ? it.label || it.code : `${it.label} (${it.code})`);
    const joined = parts.length === 1 ? parts[0] : parts.length === 2 ? `${parts[0]} and ${parts[1]}` : `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
    return <p>
        {name} {verb} {joined}.
      </p>;
  }
  const chipStyle = {
    display: "inline-flex",
    alignItems: "baseline",
    gap: "0.4rem",
    padding: "0.15rem 0.55rem",
    borderRadius: "0.375rem",
    border: "1px solid rgba(128, 128, 128, 0.25)",
    fontSize: "0.875rem",
    lineHeight: 1.5
  };
  const codeStyle = {
    fontFamily: "var(--font-mono, ui-monospace, monospace)",
    fontWeight: 600,
    fontSize: "0.8125rem"
  };
  const controlStyle = {
    color: "inherit",
    background: "transparent",
    border: "1px solid rgba(128, 128, 128, 0.3)",
    borderRadius: "0.5rem",
    fontSize: "0.875rem"
  };
  const renderChip = it => <span key={it.code} style={chipStyle} title={isCountries ? it.code : it.label || it.code}>
      {isCountries ? it.label || it.code : <span style={codeStyle}>{it.code}</span>}
      {!isCountries && it.label ? <span style={{
    opacity: 0.7
  }}>{it.label}</span> : null}
    </span>;
  const PREVIEW = 5;
  const collapsible = items.length > PREVIEW;
  const q = query.trim().toLowerCase();
  const filtered = q ? items.filter(it => it.code.toLowerCase().includes(q) || it.label && it.label.toLowerCase().includes(q)) : items;
  const expanded = open || q !== "";
  const visible = !collapsible ? items : expanded ? filtered : items.slice(0, PREVIEW);
  const toggle = () => {
    const next = !open;
    setOpen(next);
    if (!next) setQuery("");
  };
  return <div>
      <p>
        {name} {verb} the following {codes.length} {noun}:
      </p>

      {collapsible ? <input type="text" value={query} onChange={e => setQuery(e.target.value)} placeholder={`Filter ${noun}…`} aria-label={`Filter ${noun}`} style={{
    ...controlStyle,
    display: "block",
    width: "100%",
    maxWidth: "22rem",
    padding: "0.4rem 0.7rem",
    margin: "0 0 0.75rem"
  }} /> : null}

      <div style={{
    display: "flex",
    flexWrap: "wrap",
    gap: "0.4rem"
  }}>
        {visible.map(renderChip)}
      </div>

      {q && filtered.length === 0 ? <p style={{
    opacity: 0.7,
    marginTop: "0.6rem"
  }}>
          No {noun} match “{query.trim()}”.
        </p> : null}
      {q && filtered.length > 0 ? <p style={{
    opacity: 0.6,
    fontSize: "0.8125rem",
    marginTop: "0.6rem"
  }}>
          Showing {filtered.length} of {items.length}.
        </p> : null}

      {collapsible && !q ? <button type="button" aria-expanded={open} onClick={toggle} style={{
    ...controlStyle,
    display: "inline-flex",
    alignItems: "center",
    gap: "0.4rem",
    padding: "0.35rem 0.75rem",
    marginTop: "0.75rem",
    cursor: "pointer"
  }}>
          <span aria-hidden="true" style={{
    display: "inline-block",
    transform: open ? "rotate(90deg)" : "none",
    transition: "transform 0.15s ease"
  }}>
            ›
          </span>
          {open ? "Show fewer" : `and ${items.length - PREVIEW} more`}
        </button> : null}
    </div>;
};

Adyen is a global payment technology company founded in 2006 in Amsterdam, Netherlands. The company provides a single platform for accepting payments across online, mobile, and in-store channels for major enterprises worldwide including Uber, Spotify, and Microsoft.

Adyen's bank connector enables you to process ACH, SEPA, and BACS bank payments through Adyen's payment platform. This connector supports two payment flows:

* **Plaid Link**—Customers link their bank account through Plaid, and the resulting token is used to process the payment. Adyen only processes Plaid-linked payments for ACH Direct Debit accounts.
* **Direct bank details**—You provide raw bank account details directly via the API. This flow supports ACH, SEPA, and BACS schemes. See [Direct bank payments](/connections/payments/bank) for details.

## Setup

Please follow the [common Adyen instructions](./adyen) to get set up with Adyen. Next, make sure to enable the relevant bank payment methods (ACH, SEPA, or BACS) on your configured Adyen account.

The following additional settings are available.

* **Force direct bank details**—When enabled, the system skips attempting to exchange a Plaid processor token with Adyen and instead fetches raw bank details (account number, routing number, IBAN, or sort code) from Plaid directly. This saves an API call per payment and is useful when you prefer to always process with raw bank details. This setting has no effect on transactions that already use the direct `bank` payment method.

## Prerequisites

To use bank payments via Adyen, you must have:

1. **Adyen bank payments enabled:** The relevant bank payment method (ACH, SEPA, or BACS) must be enabled in your Adyen account
2. **Plaid configured:** For Plaid-linked payments, set up [Plaid](./plaid-bank) in your Gr4vy dashboard to handle bank account linking

For Plaid-linked payments, the integration flow requires customers to first link their bank account through Plaid Link, then use the resulting public token to create a transaction that is processed through Adyen.

For direct bank payments, you submit raw bank account details via the API without requiring Plaid.

## Supported countries

<ConnectorRegions data={connector} kind="countries" />

## Supported currencies

<ConnectorRegions data={connector} kind="currencies" />

## Limitations

### Refunds

Partial refunds are not supported for unsettled bank transactions. If you need to refund a bank transaction before it has settled, you must refund the full transaction amount. Once a transaction has settled, partial refunds become available.

### Payment methods

This connector supports bank accounts linked through Plaid (ACH, SEPA, and BACS) and direct bank account details submitted via the API. See [Direct bank payments](/connections/payments/bank) for the direct integration flow.

## Usage

You can create bank payments via Adyen using either Plaid Link or direct bank details.

### Option 1: Plaid Link

First, use Plaid Link to securely connect the customer's bank account. See the [Plaid integration guide](./plaid-bank-integration) for detailed instructions on implementing Plaid Link.

When the customer successfully links their account, you'll receive a `publicToken` and account metadata from Plaid.

Use the `publicToken` from Plaid to create a transaction that is processed through the Adyen bank connector.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
      transactionCreate: new TransactionCreate()
      {
          Amount = 1299,
          Currency = "USD",
          Country = "US",
          Intent = "capture",
          // The method discriminator defaults to "plaid" and isn't set explicitly
          PaymentMethod = TransactionCreatePaymentMethod.CreatePlaidPaymentMethodCreate(
              new PlaidPaymentMethodCreate()
              {
                  Token = "public-sandbox-xxxxx",
                  AccountId = "account-id-from-metadata"
              }
          ),
          Buyer = new BuyerCreate()
          {
              BillingAddress = new AddressCreate()
              {
                  FirstName = "John",
                  LastName = "Doe"
              }
          },
          PaymentServiceId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  );
  ```

  ```go Go theme={"system"}
  amount := int64(1299)
  currency := "USD"
  country := "US"
  paymentServiceId := "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

  // The method discriminator defaults to "plaid" and isn't set explicitly
  plaidPaymentMethodCreate := components.PlaidPaymentMethodCreate{
      Token:     "public-sandbox-xxxxx",
      AccountID: gr4vy.String("account-id-from-metadata"),
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodPlaidPaymentMethodCreate(plaidPaymentMethodCreate)

  transactionCreate := components.TransactionCreate{
      Amount:        amount,
      Currency:      currency,
      Country:       &country,
      Intent:        gr4vy.Pointer(components.TransactionIntentCapture),
      PaymentMethod: &paymentMethod,
      Buyer: &components.BuyerCreate{
          BillingAddress: &components.AddressCreate{
              FirstName: gr4vy.String("John"),
              LastName:  gr4vy.String("Doe"),
          },
      },
      PaymentServiceID: &paymentServiceId,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil, nil)
  ```

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
      .transactionCreate(TransactionCreate.builder()
          .amount(1299L)
          .currency("USD")
          .country("US")
          .intent(TransactionIntent.CAPTURE)
          // The method discriminator defaults to "plaid" and isn't set explicitly
          .paymentMethod(TransactionCreatePaymentMethod.of(PlaidPaymentMethodCreate.builder()
              .token("public-sandbox-xxxxx")
              .accountId("account-id-from-metadata")
              .build()))
          .buyer(BuyerCreate.builder()
              .billingAddress(AddressCreate.builder()
                  .firstName("John")
                  .lastName("Doe")
                  .build())
              .build())
          .paymentServiceId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
          .build())
      .call();

  Transaction transaction = transactionResponse.transaction().orElse(null);
  ```

  ```php PHP theme={"system"}
  $transactionCreate = new TransactionCreate(
      amount: 1299,
      currency: 'USD',
      country: 'US',
      intent: 'capture',
      // The method discriminator defaults to "plaid" and isn't set explicitly
      paymentMethod: new PlaidPaymentMethodCreate(
          token: 'public-sandbox-xxxxx',
          accountId: 'account-id-from-metadata'
      ),
      buyer: new BuyerCreate(
          billingAddress: new AddressCreate(
              firstName: 'John',
              lastName: 'Doe'
          )
      ),
      paymentServiceId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
  );
  $response = self::$sdk->transactions->create($transactionCreate);
  $transaction = $response->transaction;
  ```

  ```python Python theme={"system"}
  transaction: models.Transaction = client.transactions.create(
      amount=1299,
      currency="USD",
      country="US",
      intent="capture",
      # The method discriminator defaults to "plaid" and isn't set explicitly
      payment_method=models.PlaidPaymentMethodCreate(
          token="public-sandbox-xxxxx",
          account_id="account-id-from-metadata"
      ),
      buyer=models.BuyerCreate(
          billing_address=models.AddressCreate(
              first_name="John",
              last_name="Doe"
          )
      ),
      payment_service_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  )
  ```

  ```ts TypeScript theme={"system"}
  const transaction = await gr4vy.transactions.create({
      amount: 1299,
      currency: "USD",
      country: "US",
      intent: "capture",
      paymentMethod: {
          method: "plaid",
          token: "public-sandbox-xxxxx",
          accountId: "account-id-from-metadata"
      },
      buyer: {
          billingAddress: {
              firstName: "John",
              lastName: "Doe"
          }
      },
      paymentServiceId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  })
  ```
</CodeGroup>

**Key parameters:**

* `method` - Set to `plaid` to indicate a Plaid-linked bank account
* `token` - The public token received from Plaid Link
* `account_id` - Optional. The specific account ID from Plaid metadata if the customer linked multiple accounts
* `payment_service_id` - The UUID of your Adyen bank connection (found in Gr4vy dashboard)

The transaction is processed through Adyen as an ACH Direct Debit payment using the bank account details securely retrieved from Plaid.

### Option 2: Direct bank details

Submit raw bank account details directly via the API. Set `method` to `bank` and `scheme` to the appropriate value (`ach`, `sepa`, or `bacs`).

The following example uses the `ach` scheme. For SEPA, replace the scheme with `sepa` and provide the IBAN as the `account_number`. For BACS, replace the scheme with `bacs` and provide the sort code as the `routing_number`.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
      transactionCreate: new TransactionCreate()
      {
          Amount = 1299,
          Currency = "USD",
          Country = "US",
          Intent = "capture",
          PaymentMethod = TransactionCreatePaymentMethod.CreateACHBankPaymentMethodCreate(
              new ACHBankPaymentMethodCreate()
              {
                  AccountNumber = "1234567890",
                  RoutingNumber = "011000138",
                  AccountType = "checking",
                  AccountHolder = new BankAccountHolder()
                  {
                      FirstName = "John",
                      LastName = "Doe"
                  }
              }
          ),
          PaymentServiceId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  );
  ```

  ```go Go theme={"system"}
  amount := int64(1299)
  currency := "USD"
  country := "US"
  paymentServiceId := "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

  achPaymentMethod := components.ACHBankPaymentMethodCreate{
      AccountNumber: "1234567890",
      RoutingNumber: "011000138",
      AccountType:   components.AccountTypeChecking,
      AccountHolder: components.BankAccountHolder{
          FirstName: gr4vy.String("John"),
          LastName:  gr4vy.String("Doe"),
      },
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodACHBankPaymentMethodCreate(achPaymentMethod)

  transactionCreate := components.TransactionCreate{
      Amount:           amount,
      Currency:         currency,
      Country:          &country,
      Intent:           gr4vy.Pointer(components.TransactionIntentCapture),
      PaymentMethod:    &paymentMethod,
      PaymentServiceID: &paymentServiceId,
  }

  transaction, err := client.Transactions.Create(ctx, transactionCreate, nil, nil, nil)
  ```

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
      .transactionCreate(TransactionCreate.builder()
          .amount(1299L)
          .currency("USD")
          .country("US")
          .intent(TransactionIntent.CAPTURE)
          .paymentMethod(TransactionCreatePaymentMethod.of(ACHBankPaymentMethodCreate.builder()
              .accountNumber("1234567890")
              .routingNumber("011000138")
              .accountType(AccountType.CHECKING)
              .accountHolder(BankAccountHolder.builder()
                  .firstName("John")
                  .lastName("Doe")
                  .build())
              .build()))
          .paymentServiceId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
          .build())
      .call();

  Transaction transaction = transactionResponse.transaction().orElse(null);
  ```

  ```php PHP theme={"system"}
  $transactionCreate = new TransactionCreate(
      amount: 1299,
      currency: 'USD',
      country: 'US',
      intent: 'capture',
      paymentMethod: new ACHBankPaymentMethodCreate(
          accountNumber: '1234567890',
          routingNumber: '011000138',
          accountType: 'checking',
          accountHolder: new BankAccountHolder(
              firstName: 'John',
              lastName: 'Doe'
          )
      ),
      paymentServiceId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
  );
  $response = $sdk->transactions->create($transactionCreate);
  $transaction = $response->transaction;
  ```

  ```python Python theme={"system"}
  transaction = client.transactions.create(
      amount=1299,
      currency="USD",
      country="US",
      intent="capture",
      payment_method={
          "method": "bank",
          "scheme": "ach",
          "account_number": "1234567890",
          "routing_number": "011000138",
          "account_type": "checking",
          "account_holder": {
              "first_name": "John",
              "last_name": "Doe"
          }
      },
      payment_service_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  )
  ```

  ```ts TypeScript theme={"system"}
  const transaction = await client.transactions.create({
      amount: 1299,
      currency: "USD",
      country: "US",
      intent: "capture",
      paymentMethod: {
          method: "bank",
          scheme: "ach",
          accountNumber: "1234567890",
          routingNumber: "011000138",
          accountType: "checking",
          accountHolder: {
              firstName: "John",
              lastName: "Doe"
          }
      },
      paymentServiceId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  });
  ```
</CodeGroup>

For vaulting, recurring payments, and additional details, see the [Direct bank payments](/connections/payments/bank) guide.

## Testing

In a test environment, you can use Plaid's sandbox mode along with Adyen's test environment:

1. Configure Plaid with sandbox credentials
2. Use Plaid's test credentials to link a test bank account
3. Process test transactions through Adyen's sandbox

For direct bank details, use Adyen's test account numbers for ACH, SEPA, or BACS as documented in Adyen's testing guides.

Refer to [Plaid's testing documentation](https://plaid.com/docs/sandbox/) for available test credentials and scenarios.
