Send funds from a user's wallet
Send tokens from a user's wallet to any address on the same chain. A transfer works like an order: you create it, sign the payloads it returns, then execute it. A payload is an unsigned transaction.
Create the transfer
Send the asset_id from the catalog, the amount in that asset with qty_unit: "base", and the destination address in to. Leave out network; the transfer uses the asset's chain. Add TM-On-Behalf-Of to name the user whose wallet the funds leave. A transfer for more than the wallet holds is rejected with 403, so read the balance first.
The transfer comes back with status awaiting_signature and its payloads. Keep id and payloads.
- TypeScript
- Python
- curl
const transfer = await post(
"/v1/gateway/transfers",
{
asset_id: assetId,
qty: "5",
qty_unit: "base",
to: "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
},
forUser,
);
transfer = post(
"/v1/gateway/transfers",
{
"asset_id": asset_id,
"qty": "5",
"qty_unit": "base",
"to": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
},
for_user,
)
curl -s -X POST https://api.truemarkets.co/v1/gateway/transfers \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "TM-On-Behalf-Of: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"asset_id": "'"$ASSET_ID"'",
"qty": "5",
"qty_unit": "base",
"to": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin"
}'
{
"id": "6d5c4b3a-2f1e-4d0c-9b8a-7f6e5d4c3b2a",
"status": "awaiting_signature",
"asset_symbol": "USDC",
"chain": "solana",
"to": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
"qty": "5",
"payloads": [{ "digest": "8e1a…4f2b", "payload": "{\"organizationId\":\"…\",…}" }],
"…": "…"
}
Sign and execute
Sign each payload with your signer key, the same way you sign an order, and post the signatures in the order the payloads came back. Getting started has the signing code.
auth_type: "api_key" tells us the signer key made the signatures, not your organization API key.
Once the chain confirms a transfer, it can't be reversed. Check the address and the network before you execute.
- TypeScript
- Python
- curl
const signatures = await Promise.all(
transfer.payloads.map((p) => stamp(p.payload)),
);
const done = await post(
`/v1/gateway/transfers/${transferId}/execute`,
{
signatures,
auth_type: "api_key",
},
forUser,
);
signatures = [stamp(p["payload"]) for p in transfer["payloads"]]
done = post(
f"/v1/gateway/transfers/{transfer_id}/execute",
{
"signatures": signatures,
"auth_type": "api_key",
},
for_user,
)
# $SIGNATURES is the JSON array your code signed
curl -s -X POST https://api.truemarkets.co/v1/gateway/transfers/$TRANSFER_ID/execute \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "TM-On-Behalf-Of: $USER_ID" \
-H "Content-Type: application/json" \
-d '{
"signatures": '"$SIGNATURES"',
"auth_type": "api_key"
}'
{
"id": "6d5c4b3a-2f1e-4d0c-9b8a-7f6e5d4c3b2a",
"status": "completed",
"sent": "5",
"received": "5",
"explorer_url": "https://solscan.io/tx/4Hn8…Yt3z",
"…": "…"
}
Execute returns once the transaction has landed, with status completed. If it fails, the transfer is marked failed and you create a new one. Executing the same transfer again returns 409. To look a transfer up later, call GET /v1/gateway/transfers/{id} with the header.
Next: Trade for a user