# Wallets (/reference/wallets)

## Every wallet, each with its active deposit address

`GET /v1/wallets`

The active address is included on every row, so a table of deposit addresses is one request rather than one per wallet. A wallet whose address is still being derived, or all of whose addresses are retired, comes back without the `address` field.

### Parameters

- `limit` (query, optional, integer)
- `cursor` (query, optional, string) — Opaque cursor from the previous page's `next_cursor`.
- `customer_id` (query, optional, string (uuid))
- `chain` (query, optional, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `role` (query, optional, string, one of: customer, master, gas_station)

### Responses

- `200` — Wallets.
  - `object` (required, string)
  - `data` (required, array)
  - `has_more` (required, boolean)
  - `next_cursor` (optional, string | null) — Opaque. Pass as `cursor` for the next page. Do not construct or parse it.
  - `data` (optional, array)
    - `object` (required, string)
    - `id` (required, string (uuid))
    - `customer_id` (optional, string | null (uuid))
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `role` (required, string, one of: customer, master, gas_station)
    - `status` (required, string)
    - `external` (optional, boolean) — true when you custody it and we hold no key.
    - `account_kind` (optional, string, one of: eoa, contract) — `contract` = a smart account: a contract address with no private key, identical on every EVM chain we run the factory on, moved by our operator without ever holding gas. `eoa` = a keypair we hold.
    - `address` (optional, string) — The deposit address.
    - `memo` (optional, string | null) — Destination tag. When non-null the sender MUST include it or the deposit cannot be attributed. TON only.
    - `created_at` (required, string (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Get or create a customer's deposit address on a chain

`POST /v1/wallets`

Idempotent BY CONSTRUCTION — there is one wallet per (customer, chain). Calling again returns the same address with 200. Deriving a second address would split the customer's deposits across addresses your UI does not show.

### Request body (required)

- `customer_id` (required, string (uuid))
- `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
- `label` (optional, string)

### Responses

- `200` — The wallet already existed.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `customer_id` (optional, string | null (uuid))
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `role` (required, string, one of: customer, master, gas_station)
  - `status` (required, string)
  - `external` (optional, boolean) — true when you custody it and we hold no key.
  - `account_kind` (optional, string, one of: eoa, contract) — `contract` = a smart account: a contract address with no private key, identical on every EVM chain we run the factory on, moved by our operator without ever holding gas. `eoa` = a keypair we hold.
  - `address` (optional, string) — The deposit address.
  - `memo` (optional, string | null) — Destination tag. When non-null the sender MUST include it or the deposit cannot be attributed. TON only.
  - `created_at` (required, string (date-time))
- `201` — Derived.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `customer_id` (optional, string | null (uuid))
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `role` (required, string, one of: customer, master, gas_station)
  - `status` (required, string)
  - `external` (optional, boolean) — true when you custody it and we hold no key.
  - `account_kind` (optional, string, one of: eoa, contract) — `contract` = a smart account: a contract address with no private key, identical on every EVM chain we run the factory on, moved by our operator without ever holding gas. `eoa` = a keypair we hold.
  - `address` (optional, string) — The deposit address.
  - `memo` (optional, string | null) — Destination tag. When non-null the sender MUST include it or the deposit cannot be attributed. TON only.
  - `created_at` (required, string (date-time))
- `400` — Validation failed.
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — Customer not found.
- `422` — `chain_not_enabled` — the chain is not enabled for your project.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## GET /v1/wallets/{id}

`GET /v1/wallets/{id}`

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — The wallet, including its active address.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `customer_id` (optional, string | null (uuid))
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `role` (required, string, one of: customer, master, gas_station)
  - `status` (required, string)
  - `external` (optional, boolean) — true when you custody it and we hold no key.
  - `account_kind` (optional, string, one of: eoa, contract) — `contract` = a smart account: a contract address with no private key, identical on every EVM chain we run the factory on, moved by our operator without ever holding gas. `eoa` = a keypair we hold.
  - `address` (optional, string) — The deposit address.
  - `memo` (optional, string | null) — Destination tag. When non-null the sender MUST include it or the deposit cannot be attributed. TON only.
  - `created_at` (required, string (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — Not found.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Every address this wallet has had

`GET /v1/wallets/{id}/addresses`

Includes retired addresses. They stay monitored forever, so funds sent to an old one are still credited and you may need to explain where they came from.

### Parameters

- `id` (path, required, string (uuid))

### Responses

- `200` — Addresses.
  - `object` (required, string)
  - `data` (required, array)
  - `has_more` (required, boolean)
  - `next_cursor` (optional, string | null) — Opaque. Pass as `cursor` for the next page. Do not construct or parse it.
  - `data` (optional, array)
    - `object` (required, string)
    - `id` (required, string (uuid))
    - `wallet_id` (optional, string (uuid))
    - `address` (required, string)
    - `memo` (optional, string | null)
    - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
    - `is_primary` (optional, boolean)
    - `retired_at` (optional, string | null (date-time)) — Retired addresses stay monitored forever — funds sent to one are still credited.
    - `created_at` (optional, string (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.

## Reverse-lookup an address

`GET /v1/addresses/{address}`

### Parameters

- `address` (path, required, string)
- `chain` (query, required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)

### Responses

- `200` — The address.
  - `object` (required, string)
  - `id` (required, string (uuid))
  - `wallet_id` (optional, string (uuid))
  - `address` (required, string)
  - `memo` (optional, string | null)
  - `chain` (required, string, one of: ethereum, bsc, polygon, arbitrum, base, avalanche, tron, solana, ton, bitcoin, dogecoin, optimism, linea, zksync, scroll)
  - `is_primary` (optional, boolean)
  - `retired_at` (optional, string | null (date-time)) — Retired addresses stay monitored forever — funds sent to one are still credited.
  - `created_at` (optional, string (date-time))
- `401` — Missing, malformed, expired or revoked API key.
- `403` — The key lacks the scope, its IP allowlist rejected the source, or signing is disabled.
- `404` — Not found — also returned for another project's address, so a 404 never confirms that we custody it.
- `429` — Rate limit or quota exceeded. Honour `Retry-After`.
- `500` — Unexpected error.
- `503` — A dependency is unavailable. Retryable with backoff.