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

> ## Agent Instructions
> When building application code, use `@naturalpay/sdk` for TypeScript or `naturalpay` for Python.
> When operating Natural directly for a user, use the payments MCP at `https://mcp.natural.com`.
> When searching Natural documentation, use the docs MCP at `https://docs.natural.com/mcp`.
> Use the Natural CLI for terminal and CI automation.
> Use REST only for unsupported languages or when the user explicitly requests raw HTTP.
> Start integration development and testing in the sandbox. Do not use production unless the user explicitly requests it.
> For sandbox requests that require `customerPartyId`, list customers first. Reuse only the intended fixture; otherwise create a customer.
> REST and SDK amounts use integer minor units. Payments MCP amounts use decimal strings with a required currency code.

# Deposit and withdraw

> Move money between a linked bank account and your wallet

Pull money from a linked bank account (`eac_*`) into a wallet (`wal_*`) as a transfer (`trf_*`), or push it back out. For the transfer lifecycle, read the [Transfers overview](/guides/concepts/transfers).

<Snippet file="shared/prerequisites.mdx" />

<Snippet file="shared/mcp-callout.mdx" />

<Note>
  Link a bank account in the dashboard first. Natural returns an `eac_*` id you pass on every
  deposit and withdrawal. The account must be verified and its connection active; otherwise the call
  returns 409 `external_account_not_verified` or `external_account_connection_login_required`.
</Note>

<Snippet file="shared/cents-note.mdx" />

## Deposit into a wallet

Pull money from the bank into a wallet with [`POST /transfers/deposit`](/api-reference/transfers/initiate-deposit). Funds land in your default wallet unless you name another. The minimum deposit is `100` (\$1.00), and deposits are capped per day by your tier (`deposit_tier_daily_pull_limit_exceeded`).

<Snippet file="shared/instance-id-note.mdx" />

<CodeGroup>
  ```python Python theme={null}
  import uuid
  from naturalpay import Natural

  client = Natural()
  deposit = client.transfers.initiate_deposit(
      amount=50_000,
      currency="USD",
      external_account_id="eac_019cd1798d75c7ec27e4218aeac1d282",
      description="Wallet top-up",
      idempotency_key=str(uuid.uuid4()),
  )
  print(deposit.data.id)
  ```

  ```typescript TypeScript theme={null}
  import Natural from "@naturalpay/sdk";

  const client = new Natural();
  const deposit = await client.transfers.initiateDeposit({
    amount: 50_000,
    currency: "USD",
    externalAccountId: "eac_019cd1798d75c7ec27e4218aeac1d282",
    description: "Wallet top-up",
    idempotencyKey: crypto.randomUUID(),
  });
  console.log(deposit.data.id);
  ```

  ```bash CLI theme={null}
  natural transfers initiate-deposit \
    --amount 50000 \
    --currency USD \
    --external-account-id eac_019cd1798d75c7ec27e4218aeac1d282 \
    --description "Wallet top-up" \
    --idempotency-key "$(uuidgen)"
  ```

  ```text MCP theme={null}
  Deposit $500 into my wallet from my linked bank account.
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.natural.com/transfers/deposit \
    -H "Authorization: Bearer $NATURAL_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "data": {
        "attributes": {
          "amount": 50000,
          "currency": "USD",
          "externalAccountId": "eac_019cd1798d75c7ec27e4218aeac1d282",
          "description": "Wallet top-up"
        }
      }
    }'
  ```
</CodeGroup>

The response carries the transfer (`trf_*`) in `PROCESSING`:

<Snippet file="api-examples/transfers.initiateDeposit.response.mdx" />

A transfer moves `CREATED` to `PROCESSING` to `COMPLETED`. It can pause at `IN_REVIEW` during an approval hold. It ends at `FAILED`, `RETURNED`, `CANCELED`, or `APPROVAL_DENIED`.

## Withdraw to a bank account

Push money from a wallet to the bank with [`POST /transfers/withdraw`](/api-reference/transfers/initiate-withdrawal). Natural pulls from your default wallet unless you name another, and the wallet needs enough available balance to cover it (otherwise 409 `insufficient_funds`). Withdrawals go out over ACH by default; pass `method: "instant"` for a realtime withdrawal where your account has access, otherwise the call returns 403 `instant_withdrawals_not_enabled`.

<CodeGroup>
  ```python Python theme={null}
  withdrawal = client.transfers.initiate_withdrawal(
      amount=12_500,
      currency="USD",
      external_account_id="eac_019cd1798d75c7ec27e4218aeac1d282",
      description="Payout transfer",
      idempotency_key=str(uuid.uuid4()),
  )
  print(withdrawal.data.id)
  ```

  ```typescript TypeScript theme={null}
  const withdrawal = await client.transfers.initiateWithdrawal({
    amount: 12_500,
    currency: "USD",
    externalAccountId: "eac_019cd1798d75c7ec27e4218aeac1d282",
    description: "Payout transfer",
    idempotencyKey: crypto.randomUUID(),
  });
  console.log(withdrawal.data.id);
  ```

  ```bash CLI theme={null}
  natural transfers initiate-withdrawal \
    --amount 12500 \
    --currency USD \
    --external-account-id eac_019cd1798d75c7ec27e4218aeac1d282 \
    --description "Payout transfer" \
    --idempotency-key "$(uuidgen)"
  ```

  ```text MCP theme={null}
  Withdraw $125 from my wallet to my linked bank account.
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.natural.com/transfers/withdraw \
    -H "Authorization: Bearer $NATURAL_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "data": {
        "attributes": {
          "amount": 12500,
          "currency": "USD",
          "externalAccountId": "eac_019cd1798d75c7ec27e4218aeac1d282",
          "description": "Payout transfer"
        }
      }
    }'
  ```
</CodeGroup>

The response carries the transfer (`trf_*`) in `PROCESSING`:

<Snippet file="api-examples/transfers.initiateWithdrawal.response.mdx" />

## Confirm the balance

Deposits and withdrawals settle asynchronously, so the balance change is not immediate. Read the transfer with [`GET /transfers/{transferId}`](/api-reference/transfers/get-transfer): `status` moves `PROCESSING` to `COMPLETED`, and `expectedAvailableAt` tells you when the funds are usable. Then read the wallet to confirm a deposit landed before you spend against it, or that a withdrawal left. See [Create and manage wallets](/guides/wallets/wallets) for how `balance.available` differs from `balance.total`.

<Snippet file="shared/webhook-transfer.mdx" />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.