Build a transaction
Build an unsigned transaction (UTXO, ETH or TRON, including token transfers) and get the digests to sign.
# Build a transaction
`POST https://api.rarebl.com/open/tx/build`
Builds an unsigned transaction on any chain and returns the digests to sign. The API supplies UTXOs or nonce and fees; your keys never leave you.
**Rate class:** compute (2 requests per second, burst 10, per IP). **Available since:** Open API v2.
## 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/build" -H "Content-Type: application/json" -d '{"chain":"dash","from":"[\"XnL1FvTKqe6aWfB8NrvgbUMuWCEA3dNxfF\"]","to":"[{\"address\":\"XiM9Afap6UEb5LDkcWrg2YyA28hifkZZKM\",\"amount\":\"0.01\"}]","priority":"standard"}'`
## 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. |
## Responses
### API200 (HTTP 200): OK
A Dash transaction built from one input: a real reply (nothing was signed or broadcast).
```json
{
"status": 1,
"code": "API200",
"message": "success",
"data": {
"unsigned": {
"chain": "dash",
"format": "utxo-v1",
"tx": "0200000001139f6185036ea872d9e52bd7424ba9165f31b6479556b021fe4b8f3f42e8087a0100000000ffffffff0240420f00000000001976a91454072845a9ca039a5b585f5fd994d88d38feb31c88ac189f3419000000001976a9147fb0a45f00c25ff1cb67753221326c7c420b8b2388ac00000000",
"inputs": [
{
"txid": "7a08e8423f8f4bfe21b0569547b6315f16a94b42d72be5d972a86e0385619f13",
"vout": 1,
"address": "XnL1FvTKqe6aWfB8NrvgbUMuWCEA3dNxfF",
"value": "4.23879226",
"valueSats": "423879226",
"scriptPubKey": "76a9147fb0a45f00c25ff1cb67753221326c7c420b8b2388ac",
"scriptType": "p2pkh",
"sequence": 4294967295
}
],
"outputs": [
{
"address": "XiM9Afap6UEb5LDkcWrg2YyA28hifkZZKM",
"value": "0.01",
"valueSats": "1000000",
"change": false
},
{
"address": "XnL1FvTKqe6aWfB8NrvgbUMuWCEA3dNxfF",
"value": "4.22879",
"valueSats": "422879000",
"change": true
}
],
"fee": "0.00000226",
"feeSats": "226",
"vsize": 226,
"feeRate": "1"
},
"toSign": [
{
"index": 0,
"address": "XnL1FvTKqe6aWfB8NrvgbUMuWCEA3dNxfF",
"digest": "60f09e680a8d4d7442ec09e2e89181c568f596c6200c6a2d2f4aa15a4a8fc6b1",
"algorithm": "ecdsa-secp256k1",
"sighashType": 1,
"scriptType": "p2pkh"
}
],
"expiresAt": "2026-11-15T00:31:27Z"
},
"go": null,
"meta": {
"requestid": "0123456789abcdef",
"notices": []
}
}
```
| Field | Type | Description |
| --- | --- | --- |
| `data.unsigned` | object | The unsigned transaction. `format` is `utxo-v1`, `eth-1559-v1` or `tron-v1`. UTXO: `tx`, `psbt` (BTC/LTC), `inputs[]` (each legacy p2pkh input on BTC, LTC and DASH also carries `prevTx`, the raw previous transaction as hex), `outputs[]`, `fee`, `feeSats`, `vsize`, `feeRate`. |
| `data.toSign[]` | object[] | `{index, address, digest, algorithm, sighashType?, scriptType?}`: the 32-byte hex digests to sign. |
| `data.expiresAt` | string | ISO 8601. TRON expiration; for UTXO and ETH advisory (fees, nonce). |
### API200 (HTTP 200): OK (ETH token)
An ERC-20 (USDT) transfer on Ethereum (sample values): `unsigned.tx` carries the EIP-1559 fields, the digest is the keccak256 of the typed payload.
```json
{
"status": 1,
"code": "API200",
"message": "success",
"data": {
"unsigned": {
"chain": "eth",
"format": "eth-1559-v1",
"tx": {
"from": "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe",
"to": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"nonce": 42,
"gasLimit": "65000",
"maxFeePerGas": "18.5",
"maxPriorityFeePerGas": "1.2",
"value": "0",
"data": "0xa9059cbb000000000000000000000000dead00000000000000000000000000000000dead00000000000000000000000000000000000000000000000000000000017d7840",
"chainId": 1
}
},
"toSign": [
{
"index": 0,
"address": "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe",
"digest": "9b2c4f0a6d81e3375a40c1be52d9f8a7140c6e3bd52a97f08e1c4d63b0a5f287",
"algorithm": "ecdsa-secp256k1-recoverable"
}
],
"expiresAt": "2026-11-15T00:50:00Z"
},
"go": null,
"meta": {
"requestid": "0123456789abcdef",
"notices": []
}
}
```
### API400 (HTTP 400): Bad Request
A parameter is missing or malformed. `data.param` names it (here `chain`).
```json
{
"status": 0,
"code": "API400",
"message": "Unknown or missing chain.",
"data": {
"param": "chain"
},
"go": null,
"meta": {
"requestid": "0123456789abcdef",
"notices": []
}
}
```
### API409 (HTTP 409): Conflict
BTC, LTC or BCH: a `from` address is not watched and active yet. Start a watch with [address/watch](https://docs.rarebl.com/api/address/watch).
```json
{
"status": 0,
"code": "API409",
"message": "This address is not watched yet.",
"data": {
"reason": "not_watched"
},
"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
An output (often the change) is too small to be relayed.
```json
{
"status": 0,
"code": "API422",
"message": "An output is below the dust limit.",
"data": {
"reason": "dust_output"
},
"go": null,
"meta": {
"requestid": "0123456789abcdef",
"notices": []
}
}
```
### API429 (HTTP 429): Too Many Requests
Rate limited (compute class: 2 requests per second, burst 10, 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
- Three ways to send: [sign locally with the SDK](https://docs.rarebl.com/guides/sign-locally) (recommended), [sign the digests yourself](https://docs.rarebl.com/guides/send-a-transaction), or [hosted signing](https://docs.rarebl.com/guides/hosted-signing). See [Send a transaction](https://docs.rarebl.com/guides/send-a-transaction).
- The digest depends on the script type: legacy sighash for p2pkh, BIP143 for p2wpkh and p2sh-p2wpkh, BIP341 for p2tr key path (Schnorr), BIP143-style with FORKID (`0x41`) for BCH, keccak256 of the EIP-1559 payload for ETH and sha256 of `raw_data` for TRON. ECDSA signatures are RFC 6979 and low-S.
- ETH and TRON take `from` (one address), `to` (one recipient) and optionally `token`. ETH also takes `gasLimit`, `maxFeePerGas` and `maxPriorityFeePerGas`; TRON takes `feeLimit` (sun).
- Legacy p2pkh inputs (BTC, LTC, DASH) carry `prevTx` in `unsigned.inputs[]`. A legacy signature does not commit to the input amount, so the SDKs check that `prevTx` hashes to the input's `txid` and read the amount from it before signing.
- The [SDKs](https://docs.rarebl.com/sdks/js) build, verify and sign locally, so you rarely call this endpoint by hand. See [Send a transaction](https://docs.rarebl.com/guides/send-a-transaction).
- The ETH example shows the shape; its hex strings and digest are sample values.