> For the complete index of the 402pay docs, see [llms.txt](https://developer.402pay.co/llms.txt).

# Send from the wallet

Relay a send the dashboard signed in the browser, or record one made in an external wallet's app.

`POST https://dash.402pay.co/api/v1/wallet/transactions`

Sends coins from your wallet, one chain transaction per request. The dashboard makes these requests when someone sends from Wallet, so it takes a person signed in there, never an API key, which gets 403 `session_required`. A send that draws on several of the wallet's addresses is several requests, each with its own `Idempotency-Key`.

From a wallet created or imported in 402pay, the browser reads the [send context](https://developer.402pay.co/api/wallet/send-context.md), signs each transaction with the recovery phrase, and sends it as `signed_transaction`. 402pay checks that it pays exactly `amount` of `asset` to `to_address` from one of the wallet's addresses, records it under its hash and relays it to the network. The phrase and the encryption password never leave the browser. Before you sign, the dashboard shows the most the network fees can cost; if they rose by the time you sign, it shows the new most and asks again. A USDC send from an address with no gas goes by an EIP-3009 authorization that another of the wallet's addresses submits and pays for, as in the example. Sends are signed on Solana, Polygon and Ethereum.

From an external wallet, send in its own app, then record the send here with its `tx_hash`. The hash starts an unverified record: it does not reserve or deduct funds, and `value_usd` is zero until the chain proves the sender, recipient, asset and amount match. A mismatch fails the record. `network_fee_usd` stays zero because these records have no verified fee amount.

The transaction is `pending` until the network confirms it, then `confirmed`, or `failed` if it never lands. Follow it with [`GET /wallet/transactions/{id}`](https://developer.402pay.co/api/wallet/transactions/retrieve.md). A simulated business broadcasts nothing. Signed sends confirm on a timer; external hash records fail on that timer because the simulation has no chain evidence to verify them.

### Body

- `asset` (string, required): The coin, such as `USDC`.
- `network` (string, required): The network, such as `polygon`.
- `amount` (string, required): What this transaction pays `to_address`, as a decimal string in the coin, such as `"25.00"`, with no more [decimal places](https://developer.402pay.co/api/currencies.md#coin-amounts) than the coin's. An external wallet's record states exactly what its app sent, to as many decimal places as the coin counts on chain: USDC 6, USDT 6, BTC 8, ETH 18 and SOL 9.
- `to_address` (string, required): The recipient's address on the network.
- `speed` (string): `slow`, `standard` or `fast`, as signed. Defaults to `standard`.
- `note` (string): Up to 280 characters for your team, such as what the send was for.
- `signed_transaction` (string): Required from a wallet created or imported in 402pay. EVM: the `0x` hex of the signed EIP-1559 transaction. Solana: the base64 wire transaction.
- `funding_transaction` (string): EVM only: a signed transaction from another of the wallet's addresses that sends the gas `signed_transaction` needs, relayed first. The dashboard adds it for a token with no authorization, such as USDT on Ethereum, at an address without the network's own coin.
- `tx_hash` (string): Required from an external wallet: the hash of the send made in its own app. A hex hash is recorded in lower case.

### Errors

- 400 `idempotency_key_required` The request has no `Idempotency-Key` header.
- 400 `invalid_request` A field is missing or invalid, `signed_transaction` doesn't pay exactly `amount` to `to_address` from one of the wallet's addresses, or a field is for the other kind of wallet, such as `tx_hash` from a wallet created in 402pay. `field` names it.
- 400 `invalid_address` `to_address` isn't valid for the network, or is one of the wallet's own addresses.
- 403 `session_required` An API key sent the request. Only a person signed in to the dashboard can send.
- 404 `not_found` Your business has no wallet yet.
- 409 `insufficient_funds` The send is for more than the address holds.
- 409 `insufficient_fee_funds` The wallet doesn't hold enough of the network's own coin to pay the fee.
- 409 `duplicate_transaction` That transaction was already sent: its hash is on the wallet's history, or another business recorded it from the same address.
- 409 `transaction_rejected` The network refused it, such as when another transaction from the address got there first or the fee is too low right now. Nothing was sent, so read a fresh [send context](https://developer.402pay.co/api/wallet/send-context.md) and sign again.
- 503 `network_unavailable` The network couldn't be reached. Retry with the same `Idempotency-Key`: the same signed transaction never goes out twice.

Any request can also fail on its key or its body. See [errors](https://developer.402pay.co/api/errors.md).

Request, Browser:

```js
// On a dashboard page, whose session cookie the browser sends.
const response = await fetch("/api/v1/wallet/transactions", {
  method: "POST",
  headers: {
    "402pay-Business": businessId,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    asset: "USDC",
    network: "polygon",
    amount: "25.00",
    to_address: "0x136e44a2738dea5217e8d6745463d2a9a84d1421",
    speed: "standard",
    note: "Refund for order 1042.",
    signed_transaction: "0x<signed-transaction-from-your-browser>"
  }),
});
const { data } = await response.json();
```

Response, 201 Created:

```json
{
  "data": {
    "id": "wtx_XJPPvt18plFGNmuW",
    "kind": "wallet_transaction",
    "direction": "out",
    "status": "pending",
    "asset": "USDC",
    "network": "polygon",
    "amount": "25.00",
    "value_usd": 2500,
    "network_fee_usd": 2,
    "address": "0x6F00bCaA08D1A6De8Ce7724dd643823c978bc81F",
    "from_address": "0x6F00bCaA08D1A6De8Ce7724dd643823c978bc81F",
    "to_address": "0x136e44a2738dea5217e8d6745463d2a9a84d1421",
    "tx_hash": "0xcb6a65a380c1deecb982539aed5ca831acf85b94cfee5dc624cd34451cba0538",
    "explorer_url": "https://polygonscan.com/tx/0xcb6a65a380c1deecb982539aed5ca831acf85b94cfee5dc624cd34451cba0538",
    "payment_id": null,
    "note": "Refund for order 1042.",
    "created_at": "2026-09-29T09:37:20.808Z"
  }
}
```
