curl --request POST \
--url https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "0xdFd8302f44727A6348F702fF7B594f127dE3A902",
"token": "USDC",
"amount": "0.01"
}
'import requests
url = "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction"
payload = {
"to": "0xdFd8302f44727A6348F702fF7B594f127dE3A902",
"token": "USDC",
"amount": "0.01"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '0xdFd8302f44727A6348F702fF7B594f127dE3A902',
token: 'USDC',
amount: '0.01'
})
};
fetch('https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '0xdFd8302f44727A6348F702fF7B594f127dE3A902',
'token' => 'USDC',
'amount' => '0.01'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction"
payload := strings.NewReader("{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}"
response = http.request(request)
puts response.read_body{
"transaction": {
"from": "0x21d8d1d2d9907c051670d8c9a80bd2192d273f8d",
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"data": "0xa9059cbb000000000000000000000000dfd8302f44727a6348f702ff7b594f127de3a9020000000000000000000000000000000000000000000000000000000000002710"
},
"metadata": {
"rawAmount": "10000",
"formattedAmount": "0.01",
"tokenDecimals": 6,
"tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
}
}Build a transaction
Creates an unsigned transaction for transferring assets to another address on a specific chain. You can then use this unsigned transaction to sign and submit the transaction.
The response shape varies depending on the chain type (EIP-155, Solana, Bitcoin, Stellar, or Tron).
curl --request POST \
--url https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "0xdFd8302f44727A6348F702fF7B594f127dE3A902",
"token": "USDC",
"amount": "0.01"
}
'import requests
url = "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction"
payload = {
"to": "0xdFd8302f44727A6348F702fF7B594f127dE3A902",
"token": "USDC",
"amount": "0.01"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '0xdFd8302f44727A6348F702fF7B594f127dE3A902',
token: 'USDC',
amount: '0.01'
})
};
fetch('https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '0xdFd8302f44727A6348F702fF7B594f127dE3A902',
'token' => 'USDC',
'amount' => '0.01'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction"
payload := strings.NewReader("{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.portalhq.io/api/v3/custodians/me/clients/{clientId}/chains/{chain}/assets/send/build-transaction")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"0xdFd8302f44727A6348F702fF7B594f127dE3A902\",\n \"token\": \"USDC\",\n \"amount\": \"0.01\"\n}"
response = http.request(request)
puts response.read_body{
"transaction": {
"from": "0x21d8d1d2d9907c051670d8c9a80bd2192d273f8d",
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"data": "0xa9059cbb000000000000000000000000dfd8302f44727a6348f702ff7b594f127de3a9020000000000000000000000000000000000000000000000000000000000002710"
},
"metadata": {
"rawAmount": "10000",
"formattedAmount": "0.01",
"tokenDecimals": 6,
"tokenAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
}
}Authorizations
Portal API Key (Custodian API Key). Pass as a Bearer token in the Authorization header.
Path Parameters
The unique identifier of the client.
The blockchain chain identifier. Use either a friendly name or CAIP-2 format.
When using CAIP-2 format in URLs, ensure the colon (:) is URI-encoded as %3A.
Supported chains:
ethereum(eip155:1)sepolia(eip155:11155111)base(eip155:8453)base-sepolia(eip155:84532)polygon(eip155:137)polygon-amoy(eip155:80002)celo(eip155:42220)celo-alfajores(eip155:44787)monad(eip155:143)monad-testnet(eip155:10143)solana(solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp)solana-devnet(solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1)tron(tron:mainnet)tron-nile(tron:nile)tron-shasta(tron:shasta)stellar(stellar:pubnet)stellar-testnet(stellar:testnet)bitcoin-segwit(bip122:000000000019d6689c085ae165831e93-p2wpkh)bitcoin-segwit-testnet(bip122:000000000933ea01ad0ee984209779ba-p2wpkh)
Body
The recipient's wallet address.
The token symbol (e.g. USDC) or contract/mint address.
The amount to transfer in the token's primary denomination. Must be greater than zero.
Solana only. When true, skips fee collectors whose "Let clients
skip this fee" toggle is enabled. Collectors without the toggle are
always charged, regardless of this flag.
Was this page helpful?