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

# Transactions & signing

> Request a withdrawal, follow it from request through approval, signing, broadcast and confirmation, and sign digests directly.

## Request a withdrawal

```bash theme={null}
curl -X POST https://<api-host>/api/v1/wallets/{wallet_id}/request-withdrawal \
  -H "ACCESS-API-KEY: $KEY" -H "ACCESS-TIMESTAMP: $TS" -H "ACCESS-SIGN: $SIG" \
  -H "X-Idempotency-Key: 0c41…" \
  -H "Content-Type: application/json" \
  -d '{"asset_id": "<catalog asset id>", "amount": "0.25", "recipient_address": "0x…"}'
```

The response is the withdrawal operation with its `withdrawal_id` and initial status. Before anything is signed, the API:

* checks the key's scope (`withdrawals:create`) and wallet binding;
* validates the recipient (EIP-55 checksum) and confirms the network's chain ID matches the asset;
* reserves the amount plus fee against the available balance, so concurrent requests cannot overspend;
* applies workspace controls: the kill switch, destination whitelist and new-address hold, per-transaction and daily limits;
* evaluates policies and, if one matches or approval is required, holds the withdrawal for the approval group.

Repeating the request with the same `X-Idempotency-Key` returns the original withdrawal.

**In the console:** open the wallet → **Withdrawal** → asset, amount (or **MAX**), recipient. The console shows the planned amount and an estimated network fee before you submit.

## Lifecycle

| Status             | Meaning                                                                                                                               | Event                                          |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------- |
| `pending`          | Recorded and validated; being planned or signed.                                                                                      | `withdrawal.created`, `withdrawal.pending`     |
| `pending_approval` | Held for an approval group.                                                                                                           | `withdrawal.pending_approval`                  |
| `submitted`        | Signed and broadcast; waiting for confirmations.                                                                                      | `withdrawal.submitted`                         |
| `confirmed`        | Receipt reached the configured confirmation depth.                                                                                    | `withdrawal.confirmed`, `withdrawal.completed` |
| `failed`           | Rejected by a control, rejected by an approver, signing failed or timed out, or the transaction reverted. `status_reason` says which. | `withdrawal.failed`                            |
| `cancelled`        | Cancelled before signing.                                                                                                             | `withdrawal.cancelled`                         |

What happens after approval:

1. **Planning**: the API builds the transaction from trusted state: current nonce, EIP-1559 fee parameters, chain ID and the validated recipient. Clients never supply a transaction or a signing hash on this path.
2. **Signing**: a signing request goes to the cluster; a threshold of nodes produces the signature. The private key is never assembled.
3. **Broadcast**: the API assembles the signed transaction, verifies its hash matches the persisted withdrawal, and submits it.
4. **Confirmation**: the receipt is polled until it reaches the confirmation depth. A submitted transaction with no receipt is rebroadcast unchanged; it is never re-signed with different parameters.

## Read withdrawals and transactions

```bash theme={null}
GET /api/v1/withdrawals/{withdrawal_id}
GET /api/v1/wallets/{wallet_id}/withdrawals            # ?status=&limit=&offset=
GET /api/v1/workspaces/{workspace_id}/withdrawals
GET /api/v1/wallets/{wallet_id}/transactions           # deposits and withdrawals
GET /api/v1/workspaces/{workspace_id}/transactions
GET /api/v1/workspaces/{workspace_id}/transaction-details/{transaction_id}
```

## Sign a digest directly

For transactions your own systems build (contract calls, or networks and formats the withdrawal path does not construct) the API can sign a digest with the wallet's key while keeping the same controls.

| Route                                                 | Use                                                                                                                   |
| :---------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- |
| `POST /api/v1/web3/transaction/{wallet_id}/signTyped` | Sign a typed intent. The request is evaluated against policy and, when required, held for approval like a withdrawal. |
| `POST /api/v1/web3/transaction/{wallet_id}/signRaw`   | Sign an explicit 32-byte digest for a named network. Requires a wallet-bound key with `signing:write`.                |
| `GET /api/v1/web3/{wallet_id}/sign/{signing_id}`      | Read the status and, when complete, the signature. Requires `signing:read`.                                           |

Signing requests carry their own status and events (`signing.created`, `signing.pending_approval`, `signing.resumed`, `signing.rejected`, `signing.failed`). The API signs what it is given; it does not build or broadcast transactions on these routes.
