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

# Overview

> HD wallets, on-chain transactions, and the business USD balance used to pay gas.

The **Wallet** API manages the business HD wallet tree: deriving addresses, reading
them, signing and submitting transactions, and tracking the USD balance used to pay
gas on mainnet transfers. Wallets are scoped to the business in your token:
accessing another business's wallet returns `403`.

<Note>
  Each operation is gated on a capability granted by your plan; a missing one returns
  `403: Missing required capability: <capability>`. See the capability table on each
  endpoint.
</Note>

## The wallet object

| Attribute        | Type             | Description                                          |
| ---------------- | ---------------- | ---------------------------------------------------- |
| `id`             | `string`         | Unique wallet id (UUID).                             |
| `businessName`   | `string`         | Business the wallet belongs to.                      |
| `address`        | `string`         | On-chain address (`0x…` for EVM, base58 for Solana). |
| `chainType`      | `string`         | `EVM` or `SOLANA`.                                   |
| `purpose`        | `string`         | Logical tag (e.g. `general`, `deposit`).             |
| `derivationPath` | `string`         | HD derivation path (e.g. `m/44'/60'/0'/0/0`).        |
| `addressIndex`   | `integer`        | HD index of the address.                             |
| `isActive`       | `boolean`        | Whether the wallet is active.                        |
| `createdAt`      | `string`         | ISO 8601 UTC timestamp.                              |
| `deactivatedAt`  | `string \| null` | When the wallet was deactivated, or `null`.          |
| `metadata`       | `object \| null` | Arbitrary metadata.                                  |

## The transaction object

| Attribute      | Type             | Description                                                                           |
| -------------- | ---------------- | ------------------------------------------------------------------------------------- |
| `id`           | `string`         | Unique transaction id.                                                                |
| `type`         | `string`         | e.g. `TRANSFER`.                                                                      |
| `chainType`    | `string`         | `EVM` or `SOLANA`.                                                                    |
| `network`      | `string`         | `MAINNET` or `TESTNET`.                                                               |
| `chainId`      | `integer`        | Target chain id (e.g. `8453`).                                                        |
| `signerType`   | `string`         | e.g. `BUSINESS_HD`.                                                                   |
| `fromAddress`  | `string`         | Sending address.                                                                      |
| `addressIndex` | `integer`        | HD index of the sender.                                                               |
| `toAddress`    | `string`         | Recipient address.                                                                    |
| `amount`       | `string`         | Amount in the token's major unit, as a decimal string (e.g. `"150.00"` for 150 USDC). |
| `tokenAddress` | `string \| null` | ERC-20 contract, or `null` for a native transfer.                                     |
| `data`         | `string \| null` | Calldata (hex), if any.                                                               |
| `value`        | `string \| null` | Native value, if any.                                                                 |
| `txHash`       | `string \| null` | On-chain transaction hash; `null` until broadcast.                                    |
| `status`       | `string`         | `PENDING`, `PROCESSING`, `COMPLETED`, or `FAILED`.                                    |
| `gasUsed`      | `string \| null` | Gas units consumed; set once mined (including on revert).                             |
| `feeWei`       | `string \| null` | Fee paid in the chain's smallest unit; set even on a mined-but-reverted transfer.     |
| `error`        | `string \| null` | Failure reason; present only when `status` is `FAILED`.                               |
| `createdAt`    | `string`         | ISO 8601 UTC timestamp.                                                               |
| `updatedAt`    | `string`         | ISO 8601 UTC timestamp.                                                               |

## Transfer lifecycle and outcome delivery

[Initiate transfer](/api-reference/wallet/initiate-transfer) and sponsored
[Sign transaction](/api-reference/wallet/sign-transaction) requests are
**asynchronous by default**: the request is validated and recorded, and the API
answers `202` with the `PENDING` transaction while the on-chain execution
continues. `status` moves through:

```
PENDING ─▶ PROCESSING ─▶ COMPLETED
   │            └───────▶ FAILED      (broadcast, then reverted on-chain)
   └────────────────────▶ FAILED      (rejected before broadcast)
```

You get the outcome three ways; use them together:

1. **Poll** [Get transaction by id](/api-reference/wallet/get-transaction-by-id)
   with the `data.id` from the `202` (e.g. every 2–3 seconds) until `status` is
   `COMPLETED` or `FAILED`. This endpoint is always **authoritative**.
2. **Outcome webhook**: pass `webhookUrl` in the initiate body and the final
   transaction is POSTed to you (see below).
3. **Reconcile** anything unresolved on your side with
   [Get transaction history](/api-reference/wallet/get-transaction-history)
   filtered by `status=PENDING` or `status=PROCESSING`.

Prefer holding the request open instead? Pass `waitForCompletion: true` to get the
legacy synchronous behavior: for transfers, `201` (completed) or `422` (failed)
with the settled result; for signs, `200` with the relay result (`txHash`,
`gasUsed`, `feeWei`). Expect 3–30s latency depending on the chain.

<Note>
  Signing on a non-EVM chain with an `addressIndex` is local-only: nothing is
  broadcast, so there is no transaction to poll. Those requests always answer
  `200` with the signed transaction, regardless of `waitForCompletion`.
</Note>

<Note>
  Lost the transaction id? Re-send the initiate request with the **same
  `Idempotency-Key`**: the original `202` response, including the same `data.id`,
  is replayed without creating a second transfer.
</Note>

## Outcome webhook

When you pass `webhookUrl`, the service POSTs the final transaction there once
execution settles, in both async and sync modes:

```json theme={null}
{
  "event": "wallet.transfer.completed",
  "timestamp": "2026-07-10T22:04:11.000Z",
  "data": { "id": "9a1b…", "status": "COMPLETED", "txHash": "0xabc…", "…": "…" }
}
```

`event` is `wallet.transfer.completed` or `wallet.transfer.failed` for transfers,
and `wallet.sign.completed` or `wallet.sign.failed` for sponsored signs; `data` is
the full transaction object, including `explorerTxUrl` and (on failure) `error`.

* **Signature**: each delivery carries `x-wallet-timestamp` and
  `x-wallet-signature`, where the signature is
  `HMAC-SHA256("<timestamp>.<rawBody>")` in hex. Pass your own `webhookSecret`
  (16–256 chars) alongside `webhookUrl` in the initiate request and verify with
  the value you sent; no out-of-band secret exchange needed. The secret is held
  in memory only, never persisted or logged. Reject timestamps older than 5
  minutes to block replays.
* **Retries**: 4 attempts (1s / 5s / 15s backoff, 10s timeout each). Respond
  `2xx` quickly, before running your own processing.
* **Duplicates are possible**: key your handling on `data.id`.
* **Best-effort**: treat the webhook as a notification and confirm via
  [Get transaction by id](/api-reference/wallet/get-transaction-by-id). If no
  webhook arrives within \~30 seconds, fall back to polling.
* **URL rules**: `https` only in production; localhost, private, and
  link-local addresses are rejected with `400 INVALID_WEBHOOK_URL`.

## The balance object

| Attribute   | Type     | Description                                |
| ----------- | -------- | ------------------------------------------ |
| `balance`   | `string` | Spendable USD balance as a decimal string. |
| `currency`  | `string` | Always `USD`.                              |
| `updatedAt` | `string` | ISO 8601 UTC timestamp.                    |
