curl --request POST \
--url https://api.beta.getpara.com/v1/wallets/{walletId}/transfer \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"value": "1000000000000000",
"chainId": "1",
"tokenAddress": "<string>",
"nonce": 1,
"gasLimit": "<string>",
"maxFeePerGas": "<string>",
"maxPriorityFeePerGas": "<string>",
"gasPrice": "<string>",
"broadcast": true,
"addressScreening": true
}
'import requests
url = "https://api.beta.getpara.com/v1/wallets/{walletId}/transfer"
payload = {
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"value": "1000000000000000",
"chainId": "1",
"tokenAddress": "<string>",
"nonce": 1,
"gasLimit": "<string>",
"maxFeePerGas": "<string>",
"maxPriorityFeePerGas": "<string>",
"gasPrice": "<string>",
"broadcast": True,
"addressScreening": True
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
value: '1000000000000000',
chainId: '1',
tokenAddress: '<string>',
nonce: 1,
gasLimit: '<string>',
maxFeePerGas: '<string>',
maxPriorityFeePerGas: '<string>',
gasPrice: '<string>',
broadcast: true,
addressScreening: true
})
};
fetch('https://api.beta.getpara.com/v1/wallets/{walletId}/transfer', 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.beta.getpara.com/v1/wallets/{walletId}/transfer",
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' => '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
'value' => '1000000000000000',
'chainId' => '1',
'tokenAddress' => '<string>',
'nonce' => 1,
'gasLimit' => '<string>',
'maxFeePerGas' => '<string>',
'maxPriorityFeePerGas' => '<string>',
'gasPrice' => '<string>',
'broadcast' => true,
'addressScreening' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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.beta.getpara.com/v1/wallets/{walletId}/transfer"
payload := strings.NewReader("{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.beta.getpara.com/v1/wallets/{walletId}/transfer")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.getpara.com/v1/wallets/{walletId}/transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}"
response = http.request(request)
puts response.read_body{
"signedTransaction": "0x02f8...",
"executionMode": "legacy",
"txHash": "0x1234abcd...",
"transactionId": "550e8400-e29b-41d4-a716-446655440000"
}Transfer
High-level transfer endpoint that handles nonce, gas, and fee estimation automatically. Supports native and token transfers on EVM and Solana.
Gas sponsorship pilot: Para must enroll your partner before you use this mode. Enrollment covers all your eligible API-created, unclaimed EVM wallets, including wallets created afterward. Wallet ownership, signing readiness, permissions, and the configured per-operation gas cap still apply. Non-EVM wallets keep their existing transfer behavior.
Eligible EVM token transfers return 202 with executionMode: sponsored
and a tracking ID instead of signed transaction bytes. Require Idempotency-Key,
a supported chainId and tokenAddress, and a positive integer value in token
base units. Omit kind or use ERC20. Omit broadcast or set it to true;
leave recipient screening enabled. Native transfers, unsupported chains or tokens,
sign-only requests, transaction overrides, and disabled recipient screening
retain the existing transfer path.
202 records the request; policy, recipient screening, and per-operation gas-cap checks
run afterward. Rejections during preparation appear as tracked failed
results; uncertain outcomes remain nonterminal. Transfer/replay responses
use txHash, while transaction lookup/history uses hash after inclusion.
Pausing sponsorship admission while the partner remains enabled rejects new
eligible sponsored requests instead of falling back to wallet-paid gas.
Retrying the original request and key retrieves the same operation, including
after 24 hours or an enrollment change. It does not resume a policy review.
Partners without sponsorship enabled use the existing transfer path and its
200 response described below.
Existing policy reviews can be resumed; conditional approval policies are not
supported for sponsored transfers in this pilot.
See Gas sponsorship for tracking and review continuation.
EVM: Provide to, value, and chainId. The endpoint auto-fills nonce
(via getTransactionCount), gasLimit (via estimateGas with 20% buffer),
and fee data (maxFeePerGas/gasPrice via getFeeData) if omitted. Transaction
type is auto-detected from chain (EIP-1559 if supported, legacy otherwise).
For ERC-20 transfers, provide tokenAddress — the endpoint encodes the
transfer(address,uint256) calldata automatically.
Solana: Provide to and value (in lamports for SOL, smallest unit for SPL).
For SPL token transfers, also provide tokenAddress (the mint address).
Blockhash is fetched automatically.
Address screening is enabled by default when Para has screening configured.
Set addressScreening: false to skip recipient screening for a request.
Use kind to explicitly declare the transfer type (NATIVE, ERC20, or SPL),
or omit it to infer from the presence of tokenAddress (backwards compatible).
curl --request POST \
--url https://api.beta.getpara.com/v1/wallets/{walletId}/transfer \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"value": "1000000000000000",
"chainId": "1",
"tokenAddress": "<string>",
"nonce": 1,
"gasLimit": "<string>",
"maxFeePerGas": "<string>",
"maxPriorityFeePerGas": "<string>",
"gasPrice": "<string>",
"broadcast": true,
"addressScreening": true
}
'import requests
url = "https://api.beta.getpara.com/v1/wallets/{walletId}/transfer"
payload = {
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
"value": "1000000000000000",
"chainId": "1",
"tokenAddress": "<string>",
"nonce": 1,
"gasLimit": "<string>",
"maxFeePerGas": "<string>",
"maxPriorityFeePerGas": "<string>",
"gasPrice": "<string>",
"broadcast": True,
"addressScreening": True
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
value: '1000000000000000',
chainId: '1',
tokenAddress: '<string>',
nonce: 1,
gasLimit: '<string>',
maxFeePerGas: '<string>',
maxPriorityFeePerGas: '<string>',
gasPrice: '<string>',
broadcast: true,
addressScreening: true
})
};
fetch('https://api.beta.getpara.com/v1/wallets/{walletId}/transfer', 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.beta.getpara.com/v1/wallets/{walletId}/transfer",
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' => '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
'value' => '1000000000000000',
'chainId' => '1',
'tokenAddress' => '<string>',
'nonce' => 1,
'gasLimit' => '<string>',
'maxFeePerGas' => '<string>',
'maxPriorityFeePerGas' => '<string>',
'gasPrice' => '<string>',
'broadcast' => true,
'addressScreening' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$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.beta.getpara.com/v1/wallets/{walletId}/transfer"
payload := strings.NewReader("{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.beta.getpara.com/v1/wallets/{walletId}/transfer")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.beta.getpara.com/v1/wallets/{walletId}/transfer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"0x742d35Cc6634C0532925a3b844Bc9e7595f...\",\n \"value\": \"1000000000000000\",\n \"chainId\": \"1\",\n \"tokenAddress\": \"<string>\",\n \"nonce\": 1,\n \"gasLimit\": \"<string>\",\n \"maxFeePerGas\": \"<string>\",\n \"maxPriorityFeePerGas\": \"<string>\",\n \"gasPrice\": \"<string>\",\n \"broadcast\": true,\n \"addressScreening\": true\n}"
response = http.request(request)
puts response.read_body{
"signedTransaction": "0x02f8...",
"executionMode": "legacy",
"txHash": "0x1234abcd...",
"transactionId": "550e8400-e29b-41d4-a716-446655440000"
}Authorizations
Your partner secret key (server-side only)
Headers
UUID for request tracing. Para returns one if omitted.
Required for sponsored transfers. Save one key per transfer intent and reuse it
with the same request to recover the original operation, even after 24 hours or
sponsorship is disabled. Reuse with a different wallet or intent returns
409 IDEMPOTENCY_CONFLICT. Replays do not resume policy review.
Legacy transfers retain the optional 24-hour behavior described by IdempotencyKey.
256Path Parameters
Wallet UUID. A malformed or inaccessible wallet ID returns 404.
"0a1b2c3d-4e5f-6789-abcd-ef0123456789"
Body
Sponsored EVM transfers require an enrolled partner, an idempotency key, a supported chain and token, and a positive integer value in token base units. Omit nonce, type and gas/fee overrides; broadcast and addressScreening must be omitted or true. Requests with ordinary transfer overrides retain the legacy path.
Recipient address
"0x742d35Cc6634C0532925a3b844Bc9e7595f..."
Amount in smallest unit (wei for ETH, lamports for SOL)
"1000000000000000"
Chain ID. Required for EVM wallets, ignored for Solana.
"1"
Transfer type discriminator. EVM wallets accept NATIVE or ERC20.
Solana wallets accept NATIVE or SPL. If omitted, inferred from
tokenAddress presence (backwards compatible).
NATIVE, ERC20, SPL Token contract address. Required when kind is ERC20 or SPL. EVM: ERC-20 contract. Solana: SPL mint address.
Transaction nonce. EVM only — auto-fetched via getTransactionCount if omitted.
x >= 0Gas limit. EVM only — auto-estimated with 20% buffer if omitted.
EIP-1559 max fee per gas. EVM only — auto-fetched if omitted.
EIP-1559 max priority fee per gas. EVM only — auto-fetched if omitted.
Legacy gas price. EVM only — auto-fetched if omitted.
Transaction type: 0 (legacy) or 2 (EIP-1559). EVM only — auto-detected from chain if omitted.
0, 2 Solana network. In production, defaults to SOLANA. In beta, only SOLANA_DEVNET is allowed (and is the default).
SOLANA, SOLANA_DEVNET Whether to broadcast the signed transaction. Defaults to true. Set to false to receive only the signed transaction without broadcasting.
Whether to screen the recipient address before signing. Defaults to true when address screening is enabled for the API.
Response
Signed transaction
Signed transaction ready for broadcast. EVM: RLP-encoded hex string. Solana: base64-encoded string.
"0x02f8..."
Legacy mode; omitted by existing responses.
legacy Transaction hash. Present when broadcast is true (default). Omitted when broadcast is false.
"0x1234abcd..."
Persisted transaction record id (present only when broadcasted). Use it to poll GET /v1/wallets/{walletId}/transactions/{transactionId} or match incoming rest.transaction.confirmed / rest.transaction.failed webhooks.
"550e8400-e29b-41d4-a716-446655440000"