Skip to main content
This guide covers the full flow for sending crypto from a Yativo account to an external wallet: estimating gas fees, executing the transfer with an idempotency key, and tracking the transaction to completion.
Test this flow in the Sandbox at https://crypto-sandbox.yativo.com/api/. Sandbox transactions are simulated — no real funds move.
1

Get a gas fee estimate

Before sending, retrieve the current gas fee estimate for the target chain. This lets you show users an accurate fee breakdown and choose a priority level.
curl -X POST https://crypto-api.yativo.com/api/transactions/get-gas-price \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3JfMDFIWVo..." \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "ethereum",
    "asset": "USDC"
  }'
Response:
{
  "chain": "ethereum",
  "slow": {
    "gasPrice": "18.2",
    "estimatedFeeUsd": "0.82",
    "estimatedTimeSeconds": 120
  },
  "medium": {
    "gasPrice": "22.5",
    "estimatedFeeUsd": "1.02",
    "estimatedTimeSeconds": 30
  },
  "fast": {
    "gasPrice": "31.0",
    "estimatedFeeUsd": "1.40",
    "estimatedTimeSeconds": 10
  },
  "nativeAsset": "ETH",
  "updatedAt": "2026-03-26T11:00:00Z"
}

Priority levels

PrioritySpeedUse case
slow1–3 minNon-urgent payouts, batch processing
medium15–30 secDefault for most use cases
fast5–15 secTime-sensitive transactions
2

Send funds with an idempotency key

Use POST /transactions/send-funds to initiate the transfer. Always include an Idempotency-Key header to safely retry without double-spending.
curl -X POST https://crypto-api.yativo.com/api/transactions/send-funds \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3JfMDFIWVo..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: payout_01J2KG9MNPQ3R4S5T6UPAY001" \
  -d '{
    "accountId": "acc_01J2K9MNPQ3R4S5T6U7V8W9X0Y",
    "chain": "ethereum",
    "asset": "USDC",
    "toAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
    "amount": "100.00",
    "priority": "medium",
    "memo": "Payout for order #ORD-9821"
  }'
Response:
{
  "transactionId": "txn_01J2KH3MNPQ7R4S5T6U7VSND99",
  "accountId": "acc_01J2K9MNPQ3R4S5T6U7V8W9X0Y",
  "chain": "ethereum",
  "asset": "USDC",
  "toAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  "amount": "100.00",
  "networkFee": "1.02",
  "priority": "medium",
  "status": "pending",
  "memo": "Payout for order #ORD-9821",
  "createdAt": "2026-03-26T11:05:00Z"
}

Idempotency keys

An idempotency key is a unique string you generate and attach to a request. If the request fails or times out, you can safely retry with the same key — Yativo will return the original response instead of creating a duplicate transaction.Best practices:
  • Derive the key from your internal record ID (e.g., payout_${payoutId})
  • Keys must be unique per operation type — reusing a key for a different transfer will return the original transaction
  • Keys expire after 24 hours
3

Poll for transaction status

You can poll for the current transaction status using POST /transactions/get-transaction.
curl -X POST https://crypto-api.yativo.com/api/transactions/get-transaction \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c3JfMDFIWVo..." \
  -H "Content-Type: application/json" \
  -d '{
    "transactionId": "txn_01J2KH3MNPQ7R4S5T6U7VSND99"
  }'
Response (confirmed):
{
  "transactionId": "txn_01J2KH3MNPQ7R4S5T6U7VSND99",
  "chain": "ethereum",
  "asset": "USDC",
  "toAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  "amount": "100.00",
  "networkFee": "1.02",
  "priority": "medium",
  "status": "confirmed",
  "txHash": "0x9f3e2d1c4b7a5e8f2c9b3d6a1e4c7f2b5d8e1c4a7f6e3d2b1a8c5f4e3d2c1b",
  "blockNumber": 19847345,
  "confirmations": 12,
  "confirmedAt": "2026-03-26T11:05:42Z",
  "memo": "Payout for order #ORD-9821"
}

Transaction statuses

StatusDescription
pendingSubmitted, waiting to be broadcast
broadcastingBeing submitted to the network
mempoolIn the mempool, awaiting inclusion in a block
confirmedIncluded in a block with sufficient confirmations
failedTransaction failed (see failureReason)
4

Handle completion via webhook (recommended)

Rather than polling, register a webhook for transaction.confirmed and transaction.failed events to receive push notifications when transactions settle.
TypeScript (webhook handler)
case "transaction.confirmed": {
  const { transactionId, toAddress, amount, asset, txHash } = event.data;

  await db.payouts.markCompleted(transactionId, {
    txHash,
    confirmedAt: event.createdAt,
  });

  await notifyUserPayoutSent({ toAddress, amount, asset });
  break;
}

case "transaction.failed": {
  const { transactionId, failureReason } = event.data;

  await db.payouts.markFailed(transactionId, failureReason);
  // Refund or retry logic here
  break;
}

Common Errors

ErrorCauseFix
INSUFFICIENT_BALANCEAccount balance too lowCheck balance before sending
INVALID_ADDRESSMalformed or wrong-network addressValidate address for the target chain
DUPLICATE_IDEMPOTENCY_KEYKey reused for different parametersUse a unique key per unique transfer
AMOUNT_TOO_SMALLAmount below chain minimumCheck minimum transfer amounts per chain

Next Steps