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

# Bank Accounts & ACH

Accept ACH payments and manage bank account verification.

## Overview

Atlas supports ACH (Automated Clearing House) payments for US bank accounts. ACH is ideal for:

* Recurring billing and subscriptions
* Large transactions where card fees are prohibitive
* B2B payments
* Payouts and disbursements

## Payment Flow

1. **Collect bank details** - Use the Bank Account Element or API
2. **Verify the account** - Instant verification or microdeposits
3. **Create a mandate** - Customer authorizes debits
4. **Process payments** - Debit the account

## Bank Account Element

```tsx theme={null}
import { AtlasProvider, BankAccountElement } from '@atlas/react';

function BankForm() {
  return (
    <AtlasProvider publishableKey="pk_test_xxx">
      <BankAccountElement
        onSuccess={(bankAccount) => {
          console.log('Bank account:', bankAccount.id);
          console.log('Last 4:', bankAccount.last4);
        }}
        onError={(error) => console.error(error)}
      />
    </AtlasProvider>
  );
}
```

## API Reference

### Create Bank Account

```bash theme={null}
curl -X POST https://api.atlas.co/functions/v1/bank-accounts \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "account_holder_name": "John Doe",
    "account_holder_type": "individual",
    "routing_number": "110000000",
    "account_number": "000123456789",
    "account_type": "checking"
  }'
```

**Response:**

```json theme={null}
{
  "id": "ba_abc123",
  "object": "bank_account",
  "account_holder_name": "John Doe",
  "account_holder_type": "individual",
  "bank_name": "Test Bank",
  "last4": "6789",
  "routing_number": "110000000",
  "account_type": "checking",
  "status": "pending_verification",
  "created_at": "2025-01-21T12:00:00Z"
}
```

### Verify with Microdeposits

For accounts that can't be instantly verified:

```bash theme={null}
curl -X POST https://api.atlas.co/functions/v1/bank-accounts/ba_abc123/verify \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amounts": [32, 45]
  }'
```

### Create ACH Mandate

Authorize the customer to allow debits:

```bash theme={null}
curl -X POST https://api.atlas.co/functions/v1/bank-mandates \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "bank_account_id": "ba_abc123",
    "customer_id": "cus_xyz789",
    "mandate_type": "recurring",
    "ip_address": "192.168.1.1",
    "user_agent": "Mozilla/5.0..."
  }'
```

### Process ACH Payment

```bash theme={null}
curl -X POST https://api.atlas.co/functions/v1/bank-transfers \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "bank_account_id": "ba_abc123",
    "mandate_id": "mandate_def456",
    "amount": 10000,
    "currency": "USD",
    "description": "Invoice #1234"
  }'
```

## ACH Timeline

| Stage                | Timing                            |
| -------------------- | --------------------------------- |
| Initiated            | Immediate                         |
| Submitted to network | Same business day (before 4pm ET) |
| Pending              | 1-2 business days                 |
| Succeeded/Failed     | 3-5 business days                 |

## Test Bank Accounts

| Routing     | Account        | Result             |
| ----------- | -------------- | ------------------ |
| `110000000` | `000123456789` | Succeeds           |
| `110000000` | `000111111116` | Fails verification |
| `110000000` | `000111111113` | Account closed     |

## Webhooks

Listen for ACH events:

* `bank_transfer.initiated`
* `bank_transfer.pending`
* `bank_transfer.succeeded`
* `bank_transfer.failed`
* `bank_transfer.returned`

```javascript theme={null}
app.post('/webhooks/atlas', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'bank_transfer.succeeded':
      await fulfillOrder(event.data.metadata.order_id);
      break;
    case 'bank_transfer.failed':
    case 'bank_transfer.returned':
      await handleFailedTransfer(event.data);
      break;
  }

  res.json({ received: true });
});
```

## Return Codes

If an ACH transfer fails, check the `return_code`:

| Code | Description                               |
| ---- | ----------------------------------------- |
| R01  | Insufficient funds                        |
| R02  | Account closed                            |
| R03  | No account/unable to locate               |
| R04  | Invalid account number                    |
| R07  | Authorization revoked                     |
| R08  | Payment stopped                           |
| R10  | Customer advises not authorized           |
| R29  | Corporate customer advises not authorized |
