# Build, sign and send (hosted)

`POST https://api.rarebl.com/open/tx/send`

One call that builds, signs with the keys you send, and broadcasts.

**Rate class:** write (6 per minute, burst 3, 300 per day, per IP). **Available since:** Open API v2.

**Try It is disabled for this endpoint.** A documentation page should never collect private keys, so Try It is off here. Use the snippets from your own server or an SDK.

## Request

Send a JSON body (`Content-Type: application/json`). No API key is needed: `X-API-KEY` is reserved and ignored.

Example: `curl -X POST "https://api.rarebl.com/open/tx/send" -H "Content-Type: application/json" -H "X-Rarebl-Accept-Risk: hosted-signing" -H "Idempotency-Key: payout-2026-11-14-0002" -d '{"chain":"btc","from":"[\"bc1q7dszvzdj8lk8dd4ssad94m0t2acunaf48j455q\"]","to":"[{\"address\":\"bc1qanfrvw5lunlemvm09dthnxmwknal0fw0q7jfnm\",\"amount\":\"0.0015\"}]","priority":"standard","keys":{"encrypted":"BASE64URL_ENVELOPE_FROM_SDK"}}'`

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `X-Rarebl-Accept-Risk` | Yes | Required acknowledgement that you are sending private keys to a hosted signer. The only accepted value is `hosted-signing`; without it the API answers `API403` `risk_not_acknowledged`. Example: `hosted-signing`. |
| `Idempotency-Key` | No | Optional, as on tx/broadcast. Example: `payout-2026-11-14-0002`. |

## Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `chain` | string | Yes | The chain to build for. One of: btc, ltc, bch, dash, eth, tron. |
| `from` | array \| string | No | UTXO chains: an array of addresses we may spend from (watched on BTC/LTC/BCH, any on DASH). ETH and TRON: the sender address (one address). Use `from` or `inputs` on UTXO chains. |
| `inputs` | array | No | UTXO chains: exact inputs `[{"txid","vout"}]`, verified unspent with `gettxout`. Any UTXO chain. At most 10 inputs on the hosted endpoints. |
| `to` | array \| string | Yes | UTXO chains: recipients `[{"address","amount"}]` (one entry only). ETH and TRON: the recipient address (one recipient). `amount: "max"` sends everything less the fee. |
| `amount` | string | No | ETH and TRON: the amount in whole units (or `"max"`), as the SDKs send it. UTXO chains put the amount inside each `to` entry. |
| `change` | string | No | UTXO change address. Default: the first `from` address. |
| `feeRate` | string | No | Fee rate in sat/vB (UTXO). Use `feeRate` or `priority`. |
| `priority` | string | No | Fee choice instead of `feeRate`. One of: slow, standard, fast. |
| `rbf` | boolean | No | Signal replace-by-fee (BTC and LTC). Default true. One of: true, false. |
| `opReturn` | string | No | Optional OP_RETURN payload as hex. At most 80 bytes; UTXO chains. |
| `token` | string | No | ERC-20 (ETH) or TRC-20 (TRON) contract address for a token transfer. |
| `gasLimit` | string | No | ETH: gas limit. |
| `maxFeePerGas` | string | No | ETH: max fee per gas, Gwei. |
| `maxPriorityFeePerGas` | string | No | ETH: max priority fee per gas, Gwei. |
| `feeLimit` | integer | No | TRON: fee limit in sun. |
| `keys` | object | Yes | The private keys. `{"encrypted": "<envelope>"}`: an envelope v2 encrypted to the signer key from [tx/signer-key](https://docs.rarebl.com/api/tx/signer-key), bound to the chain, the operation (`sign` for tx/sign, `send` for tx/send) and the digests or recipients it names, valid for at most 300 seconds and single-use. Also accepted: `{"privateKeys": ["<WIF or 64-hex>"]}`, which carries no binding. See [Hosted signing](https://docs.rarebl.com/guides/hosted-signing). |

## Responses

### API200 (HTTP 200): OK

Built, signed and broadcast.

```json
{
  "status": 1,
  "code": "API200",
  "message": "success",
  "data": {
    "signed": {
      "chain": "dash",
      "hex": "0200000001139f6185036ea872d9e52bd7424ba9165f31b6479556b021fe4b8f3f42e8087a010000006a473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873ffffffff0240420f00000000001976a91454072845a9ca039a5b585f5fd994d88d38feb31c88ac189f3419000000001976a9147fb0a45f00c25ff1cb67753221326c7c420b8b2388ac00000000",
      "txid": "8235cfafa0ef70d4a5135331c6889a7c15780b7aeb3bc20721571c2a4b51ffa7"
    },
    "broadcast": {
      "txid": "8235cfafa0ef70d4a5135331c6889a7c15780b7aeb3bc20721571c2a4b51ffa7",
      "accepted": true,
      "alreadyKnown": false
    }
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `data.signed` | object | `{chain, hex \| tx, txid}`. |
| `data.broadcast` | object | `{txid, accepted, alreadyKnown}`. |

### API403 (HTTP 403): Forbidden

The header `X-Rarebl-Accept-Risk: hosted-signing` is missing.

```json
{
  "status": 0,
  "code": "API403",
  "message": "Hosted signing needs the risk acknowledgement header.",
  "data": {
    "reason": "risk_not_acknowledged"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API403 (HTTP 403): Forbidden

Every key must derive the address of an input it signs.

```json
{
  "status": 0,
  "code": "API403",
  "message": "A key does not match the input addresses.",
  "data": {
    "reason": "key_mismatch"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API403 (HTTP 403): Forbidden

The envelope (`op: "send"`) names the recipients and amounts in `bind.to` (base-unit integer strings, plus `bind.token` for a token transfer). The signer decodes the transaction itself and refuses unless it pays exactly those and any other output returns to an input address; nothing is signed.

```json
{
  "status": 0,
  "code": "API403",
  "message": "The outputs are not the ones the envelope names.",
  "data": {
    "reason": "outputs_not_bound"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API400 (HTTP 400): Bad Request

The envelope is unreadable, is a v1 envelope, names an unknown `kid`, has an `op` that does not match the route, or has an `exp` more than 300 seconds ahead. Fetch [tx/signer-key](https://docs.rarebl.com/api/tx/signer-key) again and encrypt again with SDK 0.2.0 or later.

```json
{
  "status": 0,
  "code": "API400",
  "message": "The envelope could not be read.",
  "data": {
    "reason": "bad_envelope"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API400 (HTTP 400): Bad Request

The envelope's `exp` has passed. Make a new envelope right before the request.

```json
{
  "status": 0,
  "code": "API400",
  "message": "The envelope has expired.",
  "data": {
    "reason": "envelope_expired"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API409 (HTTP 409): Conflict

An envelope opens once. Make a new envelope for every request, including a retry.

```json
{
  "status": 0,
  "code": "API409",
  "message": "The envelope was already used.",
  "data": {
    "reason": "envelope_replayed"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API400 (HTTP 400): Bad Request

The `chain` in the envelope is not the chain of the request.

```json
{
  "status": 0,
  "code": "API400",
  "message": "The envelope is for another chain.",
  "data": {
    "reason": "chain_mismatch"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API422 (HTTP 422): Unprocessable Entity

The selected inputs cannot pay the outputs plus the fee.

```json
{
  "status": 0,
  "code": "API422",
  "message": "The inputs do not cover the amount and the fee.",
  "data": {
    "reason": "insufficient_funds"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API422 (HTTP 422): Unprocessable Entity

The node refused it. `data.detail` carries its message.

```json
{
  "status": 0,
  "code": "API422",
  "message": "The node rejected the transaction.",
  "data": {
    "reason": "node_rejected",
    "detail": "min relay fee not met"
  },
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API429 (HTTP 429): Too Many Requests

Rate limited (write class: 6 per minute, burst 3, 300 per day, per IP). A `Retry-After` header says how long to wait, in seconds.

```json
{
  "status": 0,
  "code": "API429",
  "message": "Too many requests. Please retry shortly.",
  "data": null,
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

### API502 (HTTP 502): Bad Gateway

The node is unavailable, still syncing or timed out. Retry later with a short back-off.

```json
{
  "status": 0,
  "code": "API502",
  "message": "The node is unavailable or timed out. Please try again.",
  "data": null,
  "go": null,
  "meta": {
    "requestid": "0123456789abcdef",
    "notices": []
  }
}
```

## Notes

- A tx/build body plus `keys`. This really broadcasts. See [Hosted signing](https://docs.rarebl.com/guides/hosted-signing).
- The same safeguards as tx/sign apply: risk header, body-only keys, key matching, no retention, at most 10 inputs, write class. The envelope (`op: "send"`) carries `bind`, the recipients and amounts it allows; build it with `envelope.bindOf`.
