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

# The Internal Transfer Object

> Field-level reference for the Internal Transfer object, including core balance and core transaction links on each leg, the rejection block, create validations, list filters, and how it maps from the v1 Internal Transfers API.

An internal transfer moves money between two account numbers on different core accounts at Lead. You create one with `POST /v2/internal_transfers` and read it with `GET /v2/internal_transfers/{internal_transfer_id}`. POST requires an `Idempotency-Key` header. See [Idempotency](https://docs.lead.bank/api-reference/using-the-api/idempotency-v2.md).

This example is a posted transfer. Acme moved \$2,500 from its operating account to its settlement account. Lead debited the operating account's core balance and credited the settlement account's. The transfer includes a core transaction for each: one for the debit and one for the credit.

```json theme={null}
{
  "id": "internal_transfer_4KqLe9Wc4OlYa7nZsU5xF2bR8t",
  "amount": 250000,
  "currency_code": "USD",
  "description": "Daily settlement sweep",
  "status": "posted",
  "sender_account_number_id": "account_number_2fTZ4St5HSJnxzv7jdevxQnev3U",
  "sender_core_balance_id": "core_balance_2xYw9Kn3Jp7QuS2lY5mAbC0dE4f",
  "sender_core_transaction_id": "core_transaction_2pQ7Hs9Vb3NkXz6mYrT4wE1a",
  "receiver_account_number_id": "account_number_3gUA5Tu6ITKoyAw8kefwyRofw4V",
  "receiver_core_balance_id": "core_balance_3yZx0Lo4Kq8RvT3mZ6nBcD1fF5g",
  "receiver_core_transaction_id": "core_transaction_2pT1Lv3Ye6QnAc9pBuW7zH4d",
  "rejection": null,
  "metadata": {},
  "created_at": "2026-10-07T15:02:11Z",
  "updated_at": "2026-10-07T15:02:14Z"
}
```

A transfer is either posted or rejected, never both. `sender_core_transaction_id` and `receiver_core_transaction_id` are set only on a `posted` transfer, and `rejection` is set only on a `rejected` one. On a `processing` transfer all three are `null`. See [The rejection block](#the-rejection-block) for a rejected example.

## Fields

The table lists each field on the object.

| Field | Type | Description |
| - | - | - |
| `id` | string | Unique identifier, prefixed `internal_transfer_`. |
| `amount` | integer | Amount as an integer in minor units. 5000 is \$50.00. |
| `currency_code` | string | ISO 4217. `USD`. |
| `description` | string | Your description of the transfer. Required on create. |
| `status` | enum | `processing`, `posted`, or `rejected`. See [Internal Transfer Statuses](https://docs.lead.bank/v2/products/internal-transfer/statuses.md). |
| `sender_account_number_id` | string | The account number money leaves. |
| `sender_core_balance_id` | string | The core balance behind the sender account number. Resolved by Lead. |
| `sender_core_transaction_id` | string or null | The core transaction for the debit on the sender's balance. `null` until the transfer posts, and stays `null` on a rejected transfer. |
| `receiver_account_number_id` | string | The account number money arrives in. |
| `receiver_core_balance_id` | string | The core balance behind the receiver account number. Resolved by Lead. |
| `receiver_core_transaction_id` | string or null | The core transaction for the credit on the receiver's balance. `null` until the transfer posts, and stays `null` on a rejected transfer. |
| `rejection` | object or null | Set when `status` is `rejected`. See [The rejection block](#the-rejection-block). |
| `metadata` | object | Key-value pairs for your own use. Lead doesn't read them. |
| `created_at`, `updated_at` | timestamp | RFC 3339, UTC. |

## The rejection block

The table lists the fields in the rejection block.

| Field | Type | Description |
| - | - | - |
| `reason` | enum | Why the transfer was rejected after Lead accepted it. The Reason table in this section lists the values. |
| `details` | string or null | Free text about the rejection, for example which account number was inactive. |

| Reason | Populated when |
| - | - |
| `account_number_not_active` | The sender or receiver account number wasn't `active` when Lead processed the transfer. |
| `beneficiary_account_number_unrecognized` | Lead could not resolve the receiver account number. |
| `non_sufficient_funds` | The sender's core balance did not have enough available funds. |
| `ofac_rejection` | The transfer failed sanctions screening. |
| `internal_error` | Lead could not complete the transfer and has stopped retrying. |

This transfer was accepted, then rejected when Lead went to post it because the operating account's available balance had dropped below the amount. No money moved and no core transactions were created.

```json theme={null}
{
  "id": "internal_transfer_4LrMf0Xd5PmZb8oAtV6yG3cS9u",
  "amount": 250000,
  "currency_code": "USD",
  "description": "Daily settlement sweep",
  "status": "rejected",
  "sender_account_number_id": "account_number_2fTZ4St5HSJnxzv7jdevxQnev3U",
  "sender_core_balance_id": "core_balance_2xYw9Kn3Jp7QuS2lY5mAbC0dE4f",
  "sender_core_transaction_id": null,
  "receiver_account_number_id": "account_number_3gUA5Tu6ITKoyAw8kefwyRofw4V",
  "receiver_core_balance_id": "core_balance_3yZx0Lo4Kq8RvT3mZ6nBcD1fF5g",
  "receiver_core_transaction_id": null,
  "rejection": {
    "reason": "non_sufficient_funds",
    "details": "The originating account did not have sufficient balance. Balance: 184250"
  },
  "metadata": {},
  "created_at": "2026-10-08T15:00:03Z",
  "updated_at": "2026-10-08T15:00:06Z"
}
```

## Creating an internal transfer

The create request takes these fields:

| Field | Required | Description |
| - | - | - |
| `sender_account_number_id` | Yes | The account number money leaves. It must be active when Lead posts the transfer. If it isn't, the transfer is rejected with account\_number\_not\_active. |
| `receiver_account_number_id` | Yes | The account number money arrives in. It must be active when Lead posts the transfer. If it isn't, the transfer is rejected with account\_number\_not\_active. |
| `amount` | Yes | Amount as an integer in minor units. 5000 is \$50.00. |
| `currency_code` | Yes | `USD`. |
| `description` | Yes | Your description of the transfer. |
| `metadata` | No | Key-value pairs for your own use. |

Lead checks the following before it accepts the transfer. A failure returns an error and creates no transfer.

| Condition | Result |
| - | - |
| Either account number is on a user deposit balance | The request returns an error. To move money into or out of a user deposit balance, use the user deposit transactions API. |
| Both account numbers resolve to the same core account | The request returns an error. You can't use an internal transfer to move funds between account numbers belonging to the same account. |
| The core balance behind the sender account number doesn't permit internal transfers | `422`. Lead sets this permission at onboarding. |
| The sender account number is held by Lead | The request returns an error. |

Some checks depend on balances at posting time, such as available funds and account number status. They run after Lead accepts the transfer, and their results appear in the `rejection` block.

## Listing internal transfers

The `GET /v2/internal_transfers` endpoint returns a list (`objects`, `has_more`) sorted newest first. You can filter it by:

| Filter | Matches |
| - | - |
| `sender_account_number_id` | Transfers sent from the account number. |
| `receiver_account_number_id` | Transfers received by the account number. |
| `core_transaction_id` | The transfer whose `sender_core_transaction_id` or `receiver_core_transaction_id` equals the value. |
| `status` | One status value. |
| `created_at` | Transfers created in the range. |

## Coming from v1

A v2 internal transfer replaces the v1 internal transfer. Transfers created on `/v1/internal_transfer` are readable on `/v2/internal_transfers`. The create request body is unchanged.

| v1 | v2 | Notes |
| - | - | - |
| `POST /v1/internal_transfer` | `POST /v2/internal_transfers` | Resource name is plural. Same request body. |
| `sender_account_id`, `receiver_account_id` | Removed | Filter and reconcile by account number and core balance instead. |
| No balance fields | `sender_core_balance_id`, `receiver_core_balance_id` | Added in v2. Resolved from the account numbers. |
| No ledger link | `sender_core_transaction_id`, `receiver_core_transaction_id` | Added in v2. One for the sender and one for the receiver. `null` until posted. |
| No `core_transaction_id` filter | `core_transaction_id` list filter | Added in v2. Matches the sender's or the receiver's. |
| Transfers to or from an account number on a user deposit balance accepted | Rejected | Use a user deposit transaction. |
| No sender permission check | Sender core balance must permit internal transfers, else `422` | Lead sets this at onboarding. |
| Errors in the v1 shape | Errors in the [v2 shape](https://docs.lead.bank/api-reference/using-the-api/errors-v2.md) | The same-account rule is unchanged. |

## Related

* [Internal Transfer Overview](https://docs.lead.bank/v2/products/internal-transfer/overview.md)
* [Internal Transfer Statuses](https://docs.lead.bank/v2/products/internal-transfer/statuses.md)
* [The Account Number Object](https://docs.lead.bank/v2/products/account-number/account-number-object.md)
* [The Core Transaction Object](https://docs.lead.bank/products/core-transaction/core-transaction-object.md)
