> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tender.cash/llms.txt
> Use this file to discover all available pages before exploring further.

# Payouts

> Send crypto from your merchant balance to a wallet address or saved payout account

A payout sends crypto from your Tender merchant balance to an external destination — either a
raw wallet address or a saved payout account. Payouts are processed asynchronously and do not
require an OTP.

***

## How it works

<Steps>
  <Step title="Check the fee">
    Call `GET /payout/fee/{chain}/{coin}/{amount}` to see the fee and net amount before
    committing.
  </Step>

  <Step title="Submit the payout">
    Call `POST /payout/crypto` with the coin, chain, amount, and either a wallet `address` or
    a saved `payoutAccountId`.
  </Step>

  <Step title="Poll for completion">
    Call `GET /payout/{id}` until `status` is `completed` or `failed`.
  </Step>
</Steps>

***

## Prerequisites

<Card title="Authentication guide" icon="lock" href="/api-reference/authentication">
  These endpoints use Signed (HMAC) authentication — an HMAC-SHA256 signature is required on every request. See the authentication guide for code examples.
</Card>

```javascript theme={null}
const BASE = 'https://sandbox-api.tender.cash/v1/api';
// makeHeaders() → { 'x-access-id', 'x-request-id', 'x-timestamp', 'authorization', ... }
```

***

## Step 1 — Check the fee

<CodeGroup>
  ```javascript Node.js theme={null}
  const feeRes = await fetch(
    `${BASE}/payout/fee/tron/usdt/50`,
    { headers: makeHeaders() }
  );
  const { data: fee } = await feeRes.json();
  /*
  {
    amount:         50,
    amountUSD:      50.00,
    fee:            0.5,
    feeUSD:         0.50,
    amountAfterFee: 49.5,
    currency:       "usdt",
    chain:          "tron"
  }
  */
  ```

  ```python Python theme={null}
  fee_res = requests.get(
      f"{BASE}/payout/fee/tron/usdt/50",
      headers=make_headers(),
  )
  fee = fee_res.json()["data"]
  ```
</CodeGroup>

***

## Step 2 — Submit a payout to a wallet address

<CodeGroup>
  ```javascript Node.js theme={null}
  const payoutRes = await fetch(`${BASE}/payout/crypto`, {
    method: 'POST',
    headers: makeHeaders(),
    body: JSON.stringify({
      coin:    'usdt',
      chain:   'tron',
      amount:  '50',
      address: 'TQn9Y2khDD9JHTfVE5oB2h8BKWWM4LxKLT',
    }),
  });

  const { data: payout } = await payoutRes.json();
  const payoutId = payout._id;
  console.log('Status:', payout.status); // "pending"
  ```

  ```python Python theme={null}
  payout_res = requests.post(
      f"{BASE}/payout/crypto",
      headers=make_headers(),
      json={
          "coin":    "usdt",
          "chain":   "tron",
          "amount":  "50",
          "address": "TQn9Y2khDD9JHTfVE5oB2h8BKWWM4LxKLT",
      },
  )
  payout    = payout_res.json()["data"]
  payout_id = payout["_id"]
  ```
</CodeGroup>

***

## Step 2 (alt) — Payout to a saved payout account

<CodeGroup>
  ```javascript Node.js theme={null}
  const payoutRes = await fetch(`${BASE}/payout/crypto`, {
    method: 'POST',
    headers: makeHeaders(),
    body: JSON.stringify({
      coin:            'usdt',
      chain:           'tron',
      amount:          '50',
      payoutAccountId: '66aec7de809b7f45c42a49f9',
    }),
  });
  ```

  ```python Python theme={null}
  payout_res = requests.post(
      f"{BASE}/payout/crypto",
      headers=make_headers(),
      json={
          "coin":            "usdt",
          "chain":           "tron",
          "amount":          "50",
          "payoutAccountId": "66aec7de809b7f45c42a49f9",
      },
  )
  ```
</CodeGroup>

***

## Step 3 — Poll for completion

<CodeGroup>
  ```javascript Node.js theme={null}
  async function pollPayout(id, intervalMs = 8000) {
    while (true) {
      const res = await fetch(`${BASE}/payout/${id}`, { headers: makeHeaders() });
      const { data } = await res.json();

      console.log('Status:', data.status);

      if (data.status === 'completed') return data;
      if (data.status === 'failed') throw new Error('Payout failed');

      await new Promise(r => setTimeout(r, intervalMs));
    }
  }

  const result = await pollPayout(payoutId);
  ```

  ```python Python theme={null}
  import time

  def poll_payout(payout_id, interval_s=8):
      while True:
          res  = requests.get(f"{BASE}/payout/{payout_id}", headers=make_headers())
          data = res.json()["data"]

          print(f"Status: {data['status']}")

          if data["status"] == "completed":
              return data
          if data["status"] == "failed":
              raise RuntimeError("Payout failed")

          time.sleep(interval_s)
  ```
</CodeGroup>

<Tip>
  Configure a webhook to be notified when a payout completes instead of polling.
  See [Webhooks](/get-started/webhooks) for setup instructions.
</Tip>

***

## Payout status values

| Status       | Meaning                        |
| ------------ | ------------------------------ |
| `pending`    | Queued, not yet sent on-chain  |
| `processing` | Broadcast to the network       |
| `completed`  | Confirmed on-chain             |
| `failed`     | Rejected — see `failureReason` |

***

## Error handling

| Scenario                                         | Action                                                   |
| ------------------------------------------------ | -------------------------------------------------------- |
| Insufficient balance                             | Check merchant balance before submitting                 |
| Amount below minimum                             | Call the fee endpoint first; verify `amountAfterFee > 0` |
| `status: "failed"`                               | Read `failureReason` on the payout record                |
| Neither `address` nor `payoutAccountId` provided | Exactly one must be supplied; omitting both returns 400  |
