> ## 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.

# Conversions

> Swap crypto to another coin/chain or convert to a fiat payout account

A conversion moves funds from one form to another without requiring the customer to make a new
payment. There are two types:

| Type     | What it does                                                                             |
| -------- | ---------------------------------------------------------------------------------------- |
| `crypto` | Swaps a coin on one chain to a different coin or chain (e.g. USDT/Ethereum → SOL/Solana) |
| `fiat`   | Converts crypto balance to fiat and sends it to a saved payout account                   |

***

## How it works

<Steps>
  <Step title="Discover supported swap chains and coins">
    Call `GET /conversions/swap-chains` and `GET /conversions/swap-coins` to find what
    source/destination pairs are available.
  </Step>

  <Step title="Check the fee">
    Call `GET /conversions/fee/{chain}/{coin}/{amount}` to get a fee quote and estimated output
    before committing. For crypto swaps, pass `toChain` and `toCoin` as query params to get a
    destination-specific estimate.
  </Step>

  <Step title="Create the conversion">
    Call `POST /conversions` with the source coin, chain, amount, and destination. The conversion
    is queued immediately and processed asynchronously.
  </Step>

  <Step title="Poll for completion">
    Call `GET /conversions/{id}` to track `processingStages` until the conversion settles.
  </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

Always fetch a fee quote before creating a conversion so you can show the cost to the user.

<CodeGroup>
  ```javascript Node.js theme={null}
  // Crypto swap fee quote
  const feeRes = await fetch(
    `${BASE}/conversions/fee/ethereum/usdt/100?toChain=solana&toCoin=sol`,
    { headers: makeHeaders() }
  );
  const { data: fee } = await feeRes.json();
  /*
  {
    amount:          100,
    amountUSD:       100.00,
    fee:             0.5,
    feeUSD:          0.50,
    amountAfterFee:  99.5,
    estimatedOutput: 1.24,
    rate:            0.0125
  }
  */
  ```

  ```python Python theme={null}
  fee_res = requests.get(
      f"{BASE}/conversions/fee/ethereum/usdt/100",
      params={ "toChain": "solana", "toCoin": "sol" },
      headers=make_headers(),
  )
  fee = fee_res.json()["data"]
  ```
</CodeGroup>

***

## Step 2 — Create a crypto swap

<CodeGroup>
  ```javascript Node.js theme={null}
  const convRes = await fetch(`${BASE}/conversions`, {
    method: 'POST',
    headers: makeHeaders(),
    body: JSON.stringify({
      type:    'crypto',
      chain:   'ethereum',
      coin:    'usdt',
      amount:  '100',
      toChain: 'solana',
      toCoin:  'sol',
    }),
  });

  const { data } = await convRes.json();
  const conversionId = data.conversion._id;
  console.log('Status:', data.conversion.status); // "pending"
  ```

  ```python Python theme={null}
  conv_res = requests.post(
      f"{BASE}/conversions",
      headers=make_headers(),
      json={
          "type":    "crypto",
          "chain":   "ethereum",
          "coin":    "usdt",
          "amount":  "100",
          "toChain": "solana",
          "toCoin":  "sol",
      },
  )
  conversion = conv_res.json()["data"]["conversion"]
  conversion_id = conversion["_id"]
  ```
</CodeGroup>

***

## Step 2 (alt) — Create a fiat conversion

To convert to fiat, supply a `payoutAccountId` instead of `toChain`/`toCoin`.

<CodeGroup>
  ```javascript Node.js theme={null}
  const convRes = await fetch(`${BASE}/conversions`, {
    method: 'POST',
    headers: makeHeaders(),
    body: JSON.stringify({
      type:            'fiat',
      chain:           'ethereum',
      coin:            'usdt',
      amount:          '100',
      payoutAccountId: '66aec7de809b7f45c42a49f9',
    }),
  });
  ```

  ```python Python theme={null}
  conv_res = requests.post(
      f"{BASE}/conversions",
      headers=make_headers(),
      json={
          "type":            "fiat",
          "chain":           "ethereum",
          "coin":            "usdt",
          "amount":          "100",
          "payoutAccountId": "66aec7de809b7f45c42a49f9",
      },
  )
  ```
</CodeGroup>

***

## Step 3 — Poll for completion

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

      console.log('Stages:', stages);

      const allDone = Object.values(stages).every(s => s.status === 'completed');
      if (allDone) return data;

      const failed = Object.values(stages).find(s => s.status === 'failed');
      if (failed) throw new Error('Conversion failed');

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

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

  def poll_conversion(conversion_id, interval_s=8):
      while True:
          res    = requests.get(f"{BASE}/conversions/{conversion_id}", headers=make_headers())
          data   = res.json()["data"]
          stages = data["processingStages"]

          if all(s["status"] == "completed" for s in stages.values()):
              return data
          if any(s["status"] == "failed" for s in stages.values()):
              raise RuntimeError("Conversion failed")

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

***

## Processing stages

| Stage               | What happens                             |
| ------------------- | ---------------------------------------- |
| `sendForConversion` | Funds sent to the conversion provider    |
| `conversionState`   | Provider executes the swap               |
| `settleCrypto`      | Converted funds delivered to destination |

***

## Error handling

| Scenario                 | Action                                                                          |
| ------------------------ | ------------------------------------------------------------------------------- |
| Amount below minimum     | Check `fee.amountAfterFee > 0` before creating                                  |
| Unsupported swap pair    | Verify pair exists via `/conversions/swap-chains` and `/conversions/swap-coins` |
| Stage `status: "failed"` | Read the stage's `lastError` field; retry or contact support                    |
