> ## 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.

# Direct bank payments

> Accept bank payments using raw bank account details.

## Overview

Direct bank payments allow you to process bank transactions using raw bank account details instead of linking accounts through Plaid. This is useful when:

* You already collected bank account data through your own onboarding flow (for example, micro-deposits or a third-party verification service).
* Your payment processor does not support Plaid's native token exchange.
* You want to process a payment without requiring the customer to go through the Plaid Link flow.

The `bank` payment method accepts account details directly via the API and routes them to a compatible bank payment connector such as [Adyen Bank](/connections/payments/adyen-bank).

<Note>
  If you use Plaid for bank account linking, the system can also extract raw bank details from Plaid automatically when the target connector requires them. This works for ACH, SEPA, and BACS schemes. See [Plaid](/connections/payments/plaid-bank) for details.
</Note>

## Supported schemes

The `bank` payment method supports the following schemes:

| Scheme | Region | Description                                                            |
| ------ | ------ | ---------------------------------------------------------------------- |
| `ach`  | US     | ACH bank account transactions using account number and routing number. |
| `sepa` | EU/EEA | SEPA direct debit transactions using IBAN.                             |
| `bacs` | UK     | BACS direct debit transactions using account number and sort code.     |

## ACH fields

When creating a transaction or storing a payment method with the `ach` scheme, provide the following fields:

| Field            | Type    | Required | Description                                                                                |
| ---------------- | ------- | -------- | ------------------------------------------------------------------------------------------ |
| `method`         | string  | Yes      | Set to `bank`.                                                                             |
| `scheme`         | string  | Yes      | Set to `ach`.                                                                              |
| `account_number` | string  | Yes      | The bank account number.                                                                   |
| `routing_number` | string  | Yes      | The bank routing number (ABA number).                                                      |
| `account_type`   | string  | Yes      | Either `checking` or `savings`.                                                            |
| `account_holder` | object  | Yes      | The account holder's name. Provide either `first_name` and `last_name`, or `company_name`. |
| `is_tokenized`   | boolean | No       | Set to `true` if the account number is already tokenized. Defaults to `false`.             |

## SEPA fields

When creating a transaction or storing a payment method with the `sepa` scheme, provide the following fields:

| Field            | Type   | Required | Description                                                                                |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
| `method`         | string | Yes      | Set to `bank`.                                                                             |
| `scheme`         | string | Yes      | Set to `sepa`.                                                                             |
| `account_number` | string | Yes      | The IBAN (International Bank Account Number), for example `DE89370400440532013000`.        |
| `routing_number` | string | No       | The BIC (Bank Identifier Code), also known as the SWIFT code, for example `COBADEFFXXX`.   |
| `account_holder` | object | Yes      | The account holder's name. Provide either `first_name` and `last_name`, or `company_name`. |

## BACS fields

When creating a transaction or storing a payment method with the `bacs` scheme, provide the following fields:

| Field            | Type   | Required | Description                                                                                |
| ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
| `method`         | string | Yes      | Set to `bank`.                                                                             |
| `scheme`         | string | Yes      | Set to `bacs`.                                                                             |
| `account_number` | string | Yes      | The UK bank account number (8 digits), for example `31926819`.                             |
| `routing_number` | string | Yes      | The sort code (6 digits), for example `200000`.                                            |
| `account_holder` | object | Yes      | The account holder's name. Provide either `first_name` and `last_name`, or `company_name`. |

## Create a transaction

To create a direct bank payment, set the `method` to `bank` and the `scheme` to the appropriate value (`ach`, `sepa`, or `bacs`). Provide the account details in the `payment_method` object and set the `payment_service_id` to the UUID of your bank payment connector (for example, your Adyen bank connection).

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`.

See the [`POST /transactions`](/reference/transactions/new-transaction) API endpoint for more details.

<CodeGroup>
  ```csharp C# theme={"system"}
  var transaction = await client.Transactions.CreateAsync(
      transactionCreate: new TransactionCreate()
      {
          Amount = 1299,
          Currency = "USD",
          Country = "US",
          Intent = TransactionCreate.IntentEnum.Capture,
          PaymentMethod = TransactionCreatePaymentMethod.CreateACHBankPaymentMethodCreate(
              new ACHBankPaymentMethodCreate()
              {
                  Method = ACHBankPaymentMethodCreate.MethodEnum.Bank,
                  Scheme = ACHBankPaymentMethodCreate.SchemeEnum.Ach,
                  AccountNumber = "1234567890",
                  RoutingNumber = "011000138",
                  AccountType = ACHBankPaymentMethodCreate.AccountTypeEnum.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{
      Method:        components.ACHBankPaymentMethodCreateMethodBank,
      Scheme:        components.ACHBankPaymentMethodCreateSchemeAch,
      AccountNumber: "1234567890",
      RoutingNumber: "011000138",
      AccountType:   components.ACHBankPaymentMethodCreateAccountTypeChecking,
      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:           components.CreateTransactionIntentCapture,
      PaymentMethod:    &paymentMethod,
      PaymentServiceId: &paymentServiceId,
  }

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

  ```java Java theme={"system"}
  CreateTransactionResponse transactionResponse = gr4vyClient.transactions().create()
      .transactionCreate(TransactionCreate.builder()
          .amount(1299L)
          .currency("USD")
          .country("US")
          .intent(Intent.CAPTURE)
          .paymentMethod(TransactionCreatePaymentMethod.of(ACHBankPaymentMethodCreate.builder()
              .method(ACHBankPaymentMethodCreate.Method.BANK)
              .scheme(ACHBankPaymentMethodCreate.Scheme.ACH)
              .accountNumber("1234567890")
              .routingNumber("011000138")
              .accountType(ACHBankPaymentMethodCreate.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: Intent::Capture,
      paymentMethod: new ACHBankPaymentMethodCreate(
          method: ACHBankPaymentMethodCreateMethod::Bank,
          scheme: ACHBankPaymentMethodCreateScheme::Ach,
          accountNumber: '1234567890',
          routingNumber: '011000138',
          accountType: ACHBankPaymentMethodCreateAccountType::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>

**Key parameters:**

* `method` — Set to `bank` to indicate a direct bank payment.
* `scheme` — The bank scheme: `ach` (US), `sepa` (EU/EEA), or `bacs` (UK).
* `account_number` — The customer's bank account number (or IBAN for SEPA).
* `routing_number` — The bank's routing number: ABA number for ACH, routing number for SEPA, or sort code for BACS.
* `account_type` — Either `checking` or `savings`. Required for ACH only.
* `account_holder` — The name on the account. If available, send `first_name` and `last_name` for personal accounts, or `company_name` for business accounts.
* `payment_service_id` — The UUID of your bank payment connector (found in the Gr4vy dashboard).

## Vault a bank account

You can store bank account details for future use by setting `store: true` on the transaction. The system returns a `payment_method.id` that you can use for subsequent charges without collecting bank details again.

### Vault during a transaction

Set `store: true` on the transaction to vault the bank account at the same time as processing the payment.

<CodeGroup>
  ```csharp C# theme={"system"}
  var res = await client.Transactions.CreateAsync(
      transactionCreate: new TransactionCreate()
      {
          Amount = 1299,
          Currency = "USD",
          Country = "US",
          Intent = TransactionCreate.IntentEnum.Capture,
          PaymentMethod = TransactionCreatePaymentMethod.CreateACHBankPaymentMethodCreate(
              new ACHBankPaymentMethodCreate()
              {
                  Method = ACHBankPaymentMethodCreate.MethodEnum.Bank,
                  Scheme = ACHBankPaymentMethodCreate.SchemeEnum.Ach,
                  AccountNumber = "1234567890",
                  RoutingNumber = "011000138",
                  AccountType = ACHBankPaymentMethodCreate.AccountTypeEnum.Checking,
                  AccountHolder = new BankAccountHolder()
                  {
                      FirstName = "John",
                      LastName = "Doe"
                  }
              }
          ),
          Store = true,
          PaymentSource = TransactionCreate.PaymentSourceEnum.Recurring,
          MerchantInitiated = false,
          IsSubsequentPayment = false,
          PaymentServiceId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  );
  ```

  ```go Go theme={"system"}
  store := true
  merchantInitiated := false
  isSubsequent := false

  achPaymentMethod := components.ACHBankPaymentMethodCreate{
      Method:        components.ACHBankPaymentMethodCreateMethodBank,
      Scheme:        components.ACHBankPaymentMethodCreateSchemeAch,
      AccountNumber: "1234567890",
      RoutingNumber: "011000138",
      AccountType:   components.ACHBankPaymentMethodCreateAccountTypeChecking,
      AccountHolder: &components.BankAccountHolder{
          FirstName: gr4vy.String("John"),
          LastName:  gr4vy.String("Doe"),
      },
  }
  paymentMethod := components.CreateTransactionCreatePaymentMethodACHBankPaymentMethodCreate(achPaymentMethod)

  res, err := s.Transactions.Create(ctx, &components.TransactionCreate{
      Amount:              gr4vy.Int64(1299),
      Currency:            "USD",
      Country:             gr4vy.String("US"),
      Intent:              components.CreateTransactionIntentCapture,
      PaymentMethod:       &paymentMethod,
      Store:               &store,
      PaymentSource:       gr4vy.String("recurring"),
      MerchantInitiated:   &merchantInitiated,
      IsSubsequentPayment: &isSubsequent,
      PaymentServiceID:    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  })
  ```

  ```java Java theme={"system"}
  var res = sdk.transactions().create()
      .transactionCreate(TransactionCreate.builder()
          .amount(1299)
          .currency("USD")
          .country("US")
          .intent(TransactionCreate.IntentEnum.CAPTURE)
          .paymentMethod(TransactionCreatePaymentMethod.of(ACHBankPaymentMethodCreate.builder()
              .method(ACHBankPaymentMethodCreate.Method.BANK)
              .scheme(ACHBankPaymentMethodCreate.Scheme.ACH)
              .accountNumber("1234567890")
              .routingNumber("011000138")
              .accountType(ACHBankPaymentMethodCreate.AccountType.CHECKING)
              .accountHolder(BankAccountHolder.builder()
                  .firstName("John")
                  .lastName("Doe")
                  .build())
              .build()))
          .store(true)
          .paymentSource("recurring")
          .merchantInitiated(false)
          .isSubsequentPayment(false)
          .paymentServiceId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
          .build())
      .call();
  ```

  ```php PHP theme={"system"}
  $res = $sdk->transactions->create(
      transactionCreate: new Gr4vy\TransactionCreate(
          amount: 1299,
          currency: 'USD',
          country: 'US',
          intent: 'capture',
          paymentMethod: new ACHBankPaymentMethodCreate(
              method: ACHBankPaymentMethodCreateMethod::Bank,
              scheme: ACHBankPaymentMethodCreateScheme::Ach,
              accountNumber: '1234567890',
              routingNumber: '011000138',
              accountType: ACHBankPaymentMethodCreateAccountType::Checking,
              accountHolder: new BankAccountHolder(
                  firstName: 'John',
                  lastName: 'Doe'
              )
          ),
          store: true,
          paymentSource: 'recurring',
          merchantInitiated: false,
          isSubsequentPayment: false,
          paymentServiceId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
      )
  );
  ```

  ```python Python theme={"system"}
  res = 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"
          }
      },
      store=True,
      payment_source="recurring",
      merchant_initiated=False,
      is_subsequent_payment=False,
      payment_service_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  )
  ```

  ```ts TypeScript theme={"system"}
  const res = 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"
          }
      },
      store: true,
      paymentSource: "recurring",
      merchantInitiated: false,
      isSubsequentPayment: false,
      paymentServiceId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  });
  ```
</CodeGroup>

### Vault without a transaction

You can also store bank account details without processing a payment using the [`POST /payment-methods`](/reference/payment-methods/new-payment-method) endpoint. This creates a stored payment method that you can use for future transactions.

<CodeGroup>
  ```csharp C# theme={"system"}
  var res = await client.PaymentMethods.CreateAsync(
      paymentMethodCreate: new ACHBankPaymentMethodCreate()
      {
          Method = ACHBankPaymentMethodCreate.MethodEnum.Bank,
          Scheme = ACHBankPaymentMethodCreate.SchemeEnum.Ach,
          AccountNumber = "1234567890",
          RoutingNumber = "011000138",
          AccountType = ACHBankPaymentMethodCreate.AccountTypeEnum.Checking,
          AccountHolder = new BankAccountHolder()
          {
              FirstName = "John",
              LastName = "Doe"
          },
          BuyerId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  );
  ```

  ```go Go theme={"system"}
  achPaymentMethod := components.ACHBankPaymentMethodCreate{
      Method:        components.ACHBankPaymentMethodCreateMethodBank,
      Scheme:        components.ACHBankPaymentMethodCreateSchemeAch,
      AccountNumber: "1234567890",
      RoutingNumber: "011000138",
      AccountType:   components.ACHBankPaymentMethodCreateAccountTypeChecking,
      AccountHolder: &components.BankAccountHolder{
          FirstName: gr4vy.String("John"),
          LastName:  gr4vy.String("Doe"),
      },
      BuyerID: gr4vy.String("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
  }

  res, err := s.PaymentMethods.Create(ctx, achPaymentMethod)
  ```

  ```java Java theme={"system"}
  var res = sdk.paymentMethods().create()
      .paymentMethodCreate(ACHBankPaymentMethodCreate.builder()
          .method(ACHBankPaymentMethodCreate.Method.BANK)
          .scheme(ACHBankPaymentMethodCreate.Scheme.ACH)
          .accountNumber("1234567890")
          .routingNumber("011000138")
          .accountType(ACHBankPaymentMethodCreate.AccountType.CHECKING)
          .accountHolder(BankAccountHolder.builder()
              .firstName("John")
              .lastName("Doe")
              .build())
          .buyerId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
          .build())
      .call();
  ```

  ```php PHP theme={"system"}
  $res = $sdk->paymentMethods->create(
      paymentMethodCreate: new ACHBankPaymentMethodCreate(
          method: ACHBankPaymentMethodCreateMethod::Bank,
          scheme: ACHBankPaymentMethodCreateScheme::Ach,
          accountNumber: '1234567890',
          routingNumber: '011000138',
          accountType: ACHBankPaymentMethodCreateAccountType::Checking,
          accountHolder: new BankAccountHolder(
              firstName: 'John',
              lastName: 'Doe'
          ),
          buyerId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
      )
  );
  ```

  ```python Python theme={"system"}
  res = client.payment_methods.create(
      payment_method_create={
          "method": "bank",
          "scheme": "ach",
          "account_number": "1234567890",
          "routing_number": "011000138",
          "account_type": "checking",
          "account_holder": {
              "first_name": "John",
              "last_name": "Doe"
          },
          "buyer_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  )
  ```

  ```ts TypeScript theme={"system"}
  const res = await client.paymentMethods.create({
      method: "bank",
      scheme: "ach",
      accountNumber: "1234567890",
      routingNumber: "011000138",
      accountType: "checking",
      accountHolder: {
          firstName: "John",
          lastName: "Doe"
      },
      buyerId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  });
  ```
</CodeGroup>

## Recurring payments

After vaulting a bank account, use the stored `payment_method.id` to charge the account without collecting bank details again. Set `payment_source` to `recurring`, and mark the transaction as merchant-initiated and subsequent.

<CodeGroup>
  ```csharp C# theme={"system"}
  var res = await client.Transactions.CreateAsync(
      transactionCreate: new TransactionCreate()
      {
          Amount = 1299,
          Currency = "USD",
          Country = "US",
          Intent = TransactionCreate.IntentEnum.Capture,
          PaymentMethod = TransactionCreatePaymentMethod.CreateId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
          PaymentSource = TransactionCreate.PaymentSourceEnum.Recurring,
          MerchantInitiated = true,
          IsSubsequentPayment = true,
          PaymentServiceId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
      }
  );
  ```

  ```go Go theme={"system"}
  merchantInitiated := true
  isSubsequent := true

  res, err := s.Transactions.Create(ctx, &components.TransactionCreate{
      Amount:              gr4vy.Int64(1299),
      Currency:            "USD",
      Country:             gr4vy.String("US"),
      Intent:              components.CreateTransactionIntentCapture,
      PaymentMethod: &components.PaymentMethodRequest{
          Method: components.PaymentMethodRequestMethodId,
          Id:     gr4vy.String("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
      },
      PaymentSource:       gr4vy.String("recurring"),
      MerchantInitiated:   &merchantInitiated,
      IsSubsequentPayment: &isSubsequent,
      PaymentServiceID:    "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  })
  ```

  ```java Java theme={"system"}
  var res = sdk.transactions().create()
      .transactionCreate(TransactionCreate.builder()
          .amount(1299)
          .currency("USD")
          .country("US")
          .intent(TransactionCreate.IntentEnum.CAPTURE)
          .paymentMethod(PaymentMethodRequest.builder()
              .method("id")
              .id("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
              .build())
          .paymentSource("recurring")
          .merchantInitiated(true)
          .isSubsequentPayment(true)
          .paymentServiceId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
          .build())
      .call();
  ```

  ```php PHP theme={"system"}
  $res = $sdk->transactions->create(
      transactionCreate: new Gr4vy\TransactionCreate(
          amount: 1299,
          currency: 'USD',
          country: 'US',
          intent: 'capture',
          paymentMethod: new Gr4vy\PaymentMethodRequest(
              method: 'id',
              id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
          ),
          paymentSource: 'recurring',
          merchantInitiated: true,
          isSubsequentPayment: true,
          paymentServiceId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
      )
  );
  ```

  ```python Python theme={"system"}
  res = client.transactions.create(
      amount=1299,
      currency="USD",
      country="US",
      intent="capture",
      payment_method={
          "method": "id",
          "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      },
      payment_source="recurring",
      merchant_initiated=True,
      is_subsequent_payment=True,
      payment_service_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  )
  ```

  ```ts TypeScript theme={"system"}
  const res = await client.transactions.create({
      amount: 1299,
      currency: "USD",
      country: "US",
      intent: "capture",
      paymentMethod: {
          method: "id",
          id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      },
      paymentSource: "recurring",
      merchantInitiated: true,
      isSubsequentPayment: true,
      paymentServiceId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  });
  ```
</CodeGroup>

## Supported connectors

The following connectors support direct bank payments:

* **[Adyen bank](/connections/payments/adyen-bank)**—Process ACH, SEPA, and BACS transactions through Adyen using raw bank account details.

## Limitations

* **Direct routing only**—Flow rules are not supported for direct bank payments. You must specify the `payment_service_id` to route the transaction to a specific connector.
