# Bank transfers and SPEI

> A bank transfer is a push payment: instead of money being pulled from the customer's account, Stripe issues a set of bank details and the customer sends the mon

## How bank transfers work

A bank transfer is a **push** payment: instead of money being pulled from the
customer's account, Stripe issues a set of bank details and the customer sends the
money themselves from their own banking app. Nothing is collected until they do.

This is the opposite of a card payment or a direct debit, and it changes the shape
of the transaction — the payment is created, sits **pending** while the customer
goes away and makes the transfer, and only completes when Stripe matches the
incoming funds against it. That can be minutes or days later.

### Where it is available

Bank transfer is enabled per gateway in the Stripe connection settings, and must
also be enabled on your Stripe account. The rail used depends on the currency:

| Currency | Rail                          |
| -------- | ----------------------------- |
| MXN      | SPEI (Mexico)                 |
| USD      | US domestic bank transfer     |
| GBP      | UK domestic bank transfer     |
| EUR      | EU bank transfer              |
| JPY      | Japanese domestic transfer    |

A payment in any other currency will not offer bank transfer.

:::note[MXN needs a Mexican Stripe account]
SPEI is gated by the Stripe account's settlement currency. A UK, EU or US Stripe
account will reject an MXN payment with `currency mxn invalid` — the merchant's
Stripe account must be registered in Mexico and settle in MXN. This is account
configuration, not a setting in the platform.
:::

### The customer journey

- **Payment created** — the customer chooses **Pay By Bank Transfer** at checkout.
- **Instructions issued** — Stripe returns the bank details to pay to. For SPEI this
  is a CLABE and a reference; other rails return the equivalent account details.
  The customer is shown a link to those instructions.
- **Transaction is pending** — the payment is recorded as **Pending**. No money has
  moved yet.
- **Customer transfers the money** — from their own bank, using the details above.
- **Stripe matches the funds** — Stripe notifies the integration and the transaction is
  marked as Approved.

Bank transfers are for one-off payments. There is no mandate, so a bank transfer
cannot be saved as a payment method or used for recurring contracts.

## How this works in the platform

While the payment is waiting for the customer, the transaction is **Pending** and
carries a sub-status saying so:

| Field                | Value                                                            |
| -------------------- | ---------------------------------------------------------------- |
| `status`             | `PENDING`                                                        |
| `sub_status`         | `CUSTOMER_ACTION_REQUIRED`                                       |
| `sub_status_reason`  | `follow_bank_transfer_instructions`, or `partially_funded`        |

`sub_status` is on the [transaction](/platforms/reference/operations/gettransaction/) and
[payment](/platforms/reference/operations/getpayment/) objects, and can be searched on
(`criteria=sub_status=CUSTOMER_ACTION_REQUIRED`). A transaction with no `sub_status`
— or `NO_ACTION_REQUIRED` — is not waiting on anybody.

Use it to tell the two kinds of pending apart: a pending card or direct debit is
being processed by the bank, whereas a pending bank transfer is waiting for the
customer to actually send the money.

### Partial payments

If the customer transfers less than the full amount, Stripe holds what arrived and
the payment stays pending with `sub_status_reason` of `partially_funded`. The
customer is shown the amount still outstanding and can top it up against the same
instructions.

### If the customer never pays

An unfunded transfer produces no final notification from Stripe, so the integration sets an
expiry window when the payment is created. The window is the **"Bank Transfer - days
before an unpaid pending payment expires"** gateway setting (default **14 days**,
valid range 1–90).

When the window is reached, the integration re-checks the payment with Stripe:

| State at the window        | What happens                                                                 |
| -------------------------- | ---------------------------------------------------------------------------- |
| Funded after all           | The transaction is marked Approved (covers a missed notification)             |
| Funds in transit           | Re-checked every 2 days, up to 3 times, then flagged Unresolved               |
| Partly funded              | Flagged **Unresolved** for manual review — money has arrived, so it is never auto-declined |
| Still unfunded             | The payment is cancelled at Stripe and the transaction is **Declined** with "payment not received" |

Multibanco is not covered by this window — Stripe expires its vouchers itself.

### Refunds

**SPEI (MXN) payments cannot be refunded from the platform.** SPEI is a push-only rail
and cannot be reversed, so a refund attempt is blocked with a message telling the
operator to refund manually in the Stripe dashboard by returning the funds to the
customer's CLABE.

The other bank transfer rails have the same underlying limitation — the money is
returned to the customer's account via Stripe's customer balance rather than being
reversed down the original path — so treat bank transfer refunds as a manual
operation in every currency.

## Enabling bank transfer

- Enable bank transfers on your Stripe account (Stripe dashboard → Settings →
  Payment methods).
- In the Merchant Portal (**Configure** > **Payment Processing**), open the Stripe
  connection settings and turn on **Enable Bank Transfer**.
- Optionally set **"Bank Transfer - days before an unpaid pending payment expires"**.
  Leave it blank for the 14-day default.
- Select **Save**.

See [Connecting Stripe](/payment-providers/stripe-connect/) for the full list of connection
options.