> For the complete documentation index, see [llms.txt](https://docs.native.org/native-dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.native.org/native-dev/build-with-native/native-core-pool.md).

# Native Core Pool

Native Core Pool pays yield on assets held in its vault. Funds enter from an EVM chain or from a Native Core balance, sit in an earning balance, and leave through a signed withdrawal request.

This section is for teams building their own Pool experience — wallets, custodians, and front-ends that cannot route users through the Native web app. Reads require only HTTP. Deposits and withdrawals require a wallet that can sign EIP-712 typed data. The cross-chain deposit route also requires an EVM RPC endpoint.

{% content-ref url="/pages/w6yxFqDOI40x1vu99GmA" %}
[Deposit](/native-dev/build-with-native/native-core-pool/deposit.md)
{% endcontent-ref %}

{% content-ref url="/pages/qwYlKnKMTm8MFVmTz7vu" %}
[Yield](/native-dev/build-with-native/native-core-pool/yield.md)
{% endcontent-ref %}

{% content-ref url="/pages/hFz1OQMGbZMWCGJyNiAw" %}
[Withdraw](/native-dev/build-with-native/native-core-pool/withdraw.md)
{% endcontent-ref %}

{% content-ref url="/pages/aagnHfo8GxjUPwPr6ug7" %}
[Reference](/native-dev/build-with-native/native-core-pool/reference.md)
{% endcontent-ref %}

## The model

Each direction gives you one request to send and one query to poll.

|              | Deposit                                                        | Withdraw                            |
| ------------ | -------------------------------------------------------------- | ----------------------------------- |
| You send     | A vault `deposit()` on an EVM chain, or a Core `transfer`      | A signed `createWithdrawal` request |
| It lands in  | `earn_balance`                                                 | Your Native Core balance            |
| You poll     | `deposits`                                                     | `withdrawals`                       |
| Correlate on | `src_tx_hash` on the EVM route, your `cloid` on the Core route | `operation_id`                      |

A deposit cannot be cancelled or reversed. A scheduled withdrawal can be cancelled until it becomes claimable. An instant withdrawal cannot be cancelled at any point.

## Endpoints

Native Core Pool is served on mainnet at `https://api-ui.native.org`. There is no API key; requests are metered per `user_address`.

```bash
POOL_API_URL=https://api-ui.native.org
```

Every Pool operation is `POST /api/v3/earn` with a `type` field naming it.

**The HTTP status is always 200.** Branch on the `code` field in the body instead.

```json
{ "code": 0, "data": { }, "message": "success" }
```

`code: 0` is success. Anything else is a failure, and a failure body has no `data` key at all:

```json
{ "code": 131004, "message": "limit exceeds max 200" }
```

{% hint style="info" %}
Read `code` before you read `data`. A rate-limited or failed request that you treat as a 200 with an empty body reads as "no deposits yet" and never recovers. The full list is in [Error codes](/native-dev/build-with-native/native-core-pool/reference.md#error-codes).
{% endhint %}

Every response carries a `trace_id` header. Include it when you report a problem.

## Rate limits

The budgets below apply to `POST /api/v3/earn`. Requests are metered **per `user_address`**, and each `type` holds its own budget.

| Request                                                                   | Budget       |
| ------------------------------------------------------------------------- | ------------ |
| `config`                                                                  | Not metered  |
| Reads: `account`, `deposits`, `withdrawals`, `withdrawal`, `yieldHistory` | 3 per second |
| Writes: `createWithdrawal`, `claimWithdrawal`, `cancelWithdrawal`         | 1 per second |

The window resets every second. A request over the budget returns `code: 201005` and carries no `data`.

```json
{ "code": 201005, "message": "rate reach limit" }
```

The Core-internal deposit route posts to `api.native.org/trade`, which is metered separately: **1 request per second per IP**, applied before the signature is checked. That endpoint returns HTTP `429` rather than the Pool envelope; see [Rate limits & errors](/native-dev/build-with-native/native-core/reference/api-access.md#rate-limits-errors).

## Amounts and time

Amounts are **integer atom strings**, never numbers and never decimals.

| Where                     | Precision                                                                   |
| ------------------------- | --------------------------------------------------------------------------- |
| Pool balances and amounts | The asset's `balance_decimals` from `config`, currently `8` for every asset |
| Cross-chain deposit call  | The source ERC20's own `decimals`                                           |

The two precisions differ, so a cross-chain deposit requires a conversion. 1 USDT is `1000000` to the ERC20 on Ethereum (6 decimals) and `100000000` once credited to the Pool (8 decimals).

Amounts on 18-decimal tokens exceed JavaScript's safe integer range. Parse every amount with `BigInt`, not `Number`.

Every `*_unix_ms` field is a millisecond timestamp.

## Discovery

Read the routing table at runtime. Operations list and delist assets and change limits, so treat every address, id, and limit below as a read rather than a constant.

{% hint style="info" %}
Addresses, transaction hashes and signatures in the examples throughout this section are placeholders, shortened to `0x1111…1111` form for readability. Substitute full-length values, and resolve every address at runtime rather than copying one into your code as a constant.
{% endhint %}

| What you need                                           | Where it comes from                                                               |
| ------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `asset_id`, `balance_decimals`, fees, withdrawal limits | [`config`](/native-dev/build-with-native/native-core-pool/reference.md#config)    |
| Vault address and the EIP-712 domain                    | [`config`](/native-dev/build-with-native/native-core-pool/reference.md#config)    |
| Depositable ERC20s and vault addresses per chain        | [Deposit & Withdraw](/native-dev/build-with-native/deposit-withdraw.md#discovery) |

`config.assets[]` lists every asset the Pool accepts.

```bash
curl -sS "$POOL_API_URL/api/v3/earn" \
  -H 'content-type: application/json' \
  -d '{"type":"config"}'
```

```json
{
  "code": 0,
  "data": {
    "native_chain_id": 696969,
    "vault_address": "0x1111…1111",
    "fee_wallet_address": "0x2222…2222",
    "snapshot_time_utc": "00:00:00.000",
    "withdrawal_paused": false,
    "eip712_domain": {
      "name": "Native Core Earn",
      "version": "1",
      "verifyingContract": "0x1111…1111"
    },
    "assets": [
      {
        "asset_id": 2,
        "symbol": "USDT",
        "balance_decimals": 8,
        "deposit_enabled": true,
        "scheduled_withdraw_enabled": true,
        "instant_withdraw_enabled": true,
        "withdraw_pending_seconds": 10,
        "instant_fee_bps": 5,
        "min_withdraw_amount": "0",
        "max_single_withdraw_amount": "0"
      }
    ]
  },
  "message": "success"
}
```

Three of these fields carry a meaning their name does not suggest:

* `vault_address` is both the recipient of a Core-internal deposit and the EIP-712 `verifyingContract`.
* `withdraw_pending_seconds` is the wait before a scheduled withdrawal can be claimed. It is also the entire window in which the withdrawal can be cancelled.
* `min_withdraw_amount` and `max_single_withdraw_amount` use `"0"` to mean **no limit**, not a limit of zero. Only positive values are enforced.

Field definitions are in [Reference](/native-dev/build-with-native/native-core-pool/reference.md#config).

## Accounts

A Pool balance belongs to an address, and that address needs a Native Core account. The account is created by its owner's first deposit, which carries a one-time activation fee — see [Deposit](/native-dev/build-with-native/deposit-withdraw/deposit.md#2-size-the-activation-fee).

An address can have **one withdrawal in flight per asset**. A USDT withdrawal does not block a USDC one. Check `active_withdraw_operation_id` on that asset's entry in [`account`](/native-dev/build-with-native/native-core-pool/reference.md#account) `balances[]` before creating another. An empty string means nothing is in flight for that asset.

Credit accounts cannot deposit into or withdraw from the Pool. See [Account Types](/native-dev/build-with-native/native-core/concepts/account-types.md).
