---
url: /exchange/api/exchanges.md
---
# API of Exchanges 📝

## Introduction

The Exchanges API is the core swap surface of p3p. Use it to discover what's tradable, get the best quote across every aggregated liquidity source, lock that quote into an on chain swap, and track it to completion.

All endpoints below require an `api-key` header.

```http
api-key: YOUR_P3P_API_KEY
```

::: tip Partner key = your fee
If you authenticate with **your partner key** (from the [Partner Dashboard](https://p3p.xyz/partner)), the trade is attributed to you and your fee is automatically deducted from `amount_to` — on both `/exchange/rate` and `/exchange/create`. A generic developer key works for calling the endpoints but applies no fee and earns nothing. `opts.partner_id` in the body is **not** used for identity — only the key matters. See [Earn revenue](./getting-started#earn-revenue).
:::

## Endpoints

***

## 1. Get Chains {#get-chains}

GET `/chains`&#x20;

Returns every chain currently enabled on p3p.

::: code-group

```bash [curl]
curl https://api.p3p.xyz/chains \
  -H "api-key: YOUR_P3P_API_KEY"
```

```ts [fetch]
const chains = await fetch("https://api.p3p.xyz/chains", {
  headers: { "api-key": "YOUR_P3P_API_KEY" },
}).then((r) => r.json());
```

:::

```json
{
  "status": 200,
  "message": "ok",
  "data": [
    {
      "id": 0,
      "key": "btc",
      "name": "Bitcoin",
      "display": "BTC Chain",
      "color": "#F7931A",
      "logo": "",
      "icon": "token:btc",
      "explorer": {
        "address": "https://mempool.space/address/%s",
        "tx": "https://mempool.space/tx/%s"
      },
      "website": "https://bitcoin.org",
      "vm": "BVM",
      "validation": [
        "^(1[1-9A-HJ-NP-Za-km-z]{25,34}|3[1-9A-HJ-NP-Za-km-z]{25,34}|bc1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{8,87})$"
      ],
      "defaults": ["btc"],
      "tags": ["bitcoin", "btc", "xbt", "satoshi"],
      "enabled": true
    },
    {
      "id": 1,
      "key": "eth",
      "name": "Ethereum",
      "display": "ETH Chain",
      "color": "#627EEA",
      "logo": "",
      "icon": "token:eth",
      "explorer": {
        "address": "https://etherscan.io/address/%s",
        "tx": "https://etherscan.io/tx/%s"
      },
      "website": "https://ethereum.org",
      "vm": "EVM",
      "validation": [
        "^(0x)[0-9A-Fa-f]{40}$"
      ],
      "defaults": ["eth", "usdt", "usdc", "dai"],
      "tags": ["ethereum", "eth", "eht", "vitalik"],
      "enabled": true
    }
  ]
}
```

***

## 2. Get Tokens {#get-tokens}

GET `/tokens`&#x20;

Returns enabled tokens grouped by chain.

```bash
curl https://api.p3p.xyz/tokens \
  -H "api-key: YOUR_P3P_API_KEY"
```

```json
{
  "eth": [
    { "key": "eth", "name": "Ether", "symbol": "ETH", "decimals": 18, "rate": "3421.8", "address": "", "native": true, "enabled": true },
    { "key": "usdt", "name": "Tether", "symbol": "USDT", "decimals": 6, "rate": "1.0", "address": "0xdac17f958d2ee523a2206206994597c13d831ec7", "native": false, "enabled": true }
  ],
  "ton": [
    { "key": "ton", "name": "Toncoin", "symbol": "TON", "decimals": 9, "rate": "5.23", "address": "", "native": true, "enabled": true },
    { "key": "usdt", "name": "USDT (TON)", "symbol": "USDT", "decimals": 6, "rate": "1.0", "address": "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs", "native": false, "enabled": true }
  ]
}
```

***

## 3. Get Rates {#get-rates}

GET `/rates`&#x20;

Returns live market reference rates for every supported asset, sourced from on chain oracles.

```bash
curl https://api.p3p.xyz/rates \
  -H "api-key: YOUR_P3P_API_KEY"
```

```json
{
  "btc": 98234.56,
  "eth": 3421.8,
  "ton": 5.23,
  "usdt": 1.0,
  "usdc": 1.0,
  "sol": 142.35
}
```

***

## 4. Quote Exchange Rate {#quote-exchange-rate}

POST `/exchange/rate`&#x20;

Aggregate rates from every active liquidity source and return the best (or all of them).

**Body**

| Field             | Type    | Required | Description                                         |
| ----------------- | ------- | -------- | --------------------------------------------------- |
| `chain_from`      | string  | yes      | Source chain key                                    |
| `token_from`      | string  | yes      | Source token key                                    |
| `amount_from`     | string  | yes      | Amount in display units                             |
| `chain_to`        | string  | yes      | Destination chain key                               |
| `token_to`        | string  | yes      | Destination token key                               |
| `opts.best`       | boolean | no       | Sort by best rate (default)                         |
| `opts.fastest`    | boolean | no       | Sort by fastest rate instead of best                |
| `opts.partner_id` | string  | no       | Ignored for attribution — your fee/identity come from the partner `api-key` header. See [Earn revenue](./getting-started#earn-revenue). |

::: code-group

```bash [curl]
curl -X POST https://api.p3p.xyz/exchange/rate \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_P3P_API_KEY" \
  -d '{
    "chain_from": "eth",
    "token_from": "eth",
    "amount_from": "0.1",
    "chain_to": "ton",
    "token_to": "ton",
    "opts": { "best": true }
  }'
```

```ts [fetch]
const rate = await fetch("https://api.p3p.xyz/exchange/rate", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "api-key": "YOUR_P3P_API_KEY",
  },
  body: JSON.stringify({
    chain_from: "eth",
    token_from: "eth",
    amount_from: "0.1",
    chain_to: "ton",
    token_to: "ton",
    opts: { best: true },
  }),
}).then((r) => r.json());
```

:::

```json
{
  "type": "crypto",
  "path_from": "eth.eth",
  "path_to": "ton.ton",
  "amount_from": "0.1",
  "amount_to": "342.18",
  "direction": "exact_input",
  "amount_from_unit": 0.1,
  "amount_to_unit": 342.18,
  "rate": "3421.8",
  "impact": "0.01",
  "duration": 90,
  "boosted": false
}
```

***

## 5. Create Exchange {#create-exchange}

POST `/exchange/create`&#x20;

Lock a rate, create an exchange and receive a deposit address.

**Body**

| Field             | Type    | Required | Description                                         |
| ----------------- | ------- | -------- | --------------------------------------------------- |
| `chain_from`      | string  | yes      | Source chain key                                    |
| `token_from`      | string  | yes      | Source token key                                    |
| `amount_from`     | string  | yes      | Amount in display units                             |
| `chain_to`        | string  | yes      | Destination chain key                               |
| `token_to`        | string  | yes      | Destination token key                               |
| `wallet_to`       | string  | yes      | Recipient address on the destination chain          |
| `wallet_refund`   | string  | no       | Refund address if the swap cannot complete          |
| `wallet_from`     | string  | no       | The user's source address (some chains need it)     |
| `opts.best`       | boolean | no       | Sort by best rate (default)                         |
| `opts.fastest`    | boolean | no       | Sort by fastest rate instead of best                |
| `opts.tg.id`       | string  | no       | Telegram user/chat ID. Stored with the exchange so you can correlate it back to your own user. |
| `opts.tg.username` | string  | no       | Telegram username. Stored with the exchange.        |
| `opts.partner_id` | string  | no       | Ignored for attribution — your fee/identity come from the partner `api-key` header. See [Earn revenue](./getting-started#earn-revenue). |

::: info Address Validation
All provided addresses (`wallet_to`, `wallet_refund`, `wallet_from`) are validated against the respective chain's validation rules. Use the `validation` regex patterns from **Get Chains** to validate user input on your client before submitting to the API. Each chain supports specific address formats (e.g. Bitcoin: `p2pkh`, `p2sh`, `bech32`; EVM chains: 40 hex characters prefixed with `0x`; Solana: 43-44 base58 characters).
:::

::: code-group

```bash [curl]
curl -X POST https://api.p3p.xyz/exchange/create \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_P3P_API_KEY" \
  -d '{
    "chain_from": "eth", "token_from": "eth", "amount_from": "0.1",
    "chain_to":   "ton", "token_to":   "ton",
    "wallet_to":     "UQAbc...XYZ",
    "wallet_refund": "0xRefund...address",
    "opts": { "tg": { "id": "123456789", "username": "alice" } }
  }'
# Authenticate with your PARTNER api-key (above) to attribute the trade and apply your fee.
```

```ts [fetch]
const exchange = await fetch("https://api.p3p.xyz/exchange/create", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "api-key": "YOUR_P3P_API_KEY",
  },
  body: JSON.stringify({
    chain_from: "eth",
    token_from: "eth",
    amount_from: "0.1",
    chain_to: "ton",
    token_to: "ton",
    wallet_to: "UQAbc...XYZ",
    wallet_refund: "0xRefund...address",
    opts: { tg: { id: "123456789", username: "alice" } }, // your own identifier, stored with the exchange
  }),
}).then((r) => r.json()); // attribution + fee come from the partner api-key header above
```

:::

```json
{
  "created_at": "2026-05-24T10:30:00Z",
  "id": "ex_8f4c2a...",
  "type": "crypto",
  "chain_from": "eth",
  "token_from": "eth",
  "amount_from": "0.1",
  "chain_to": "ton",
  "token_to": "ton",
  "amount_to": "342.18",
  "amount_to_unit": 342.18,
  "wallet_refund": "0xRefund...address",
  "wallet_from": "",
  "wallet_to": "UQAbc...XYZ",
  "deposit_address": "0xDepositAddressGeneratedForYou",
  "rate": "3421.8",
  "impact": "0.01",
  "duration": 90
}
```

**For partner exchanges** (when using `api-key` header): The response returns `hash` instead of `id`:

```json
{
  "created_at": "2026-05-24T10:30:00Z",
  "hash": "A7K2M9X5B3C1D8F4",
  "type": "crypto",
  "chain_from": "eth",
  "token_from": "eth",
  "amount_from": "0.1",
  "chain_to": "ton",
  "token_to": "ton",
  "amount_to": "342.18",
  "amount_to_unit": 342.18,
  "wallet_to": "UQAbc...XYZ",
  "deposit_address": "0xDepositAddressGeneratedForYou",
  "rate": "3421.8",
  "impact": "0.01",
  "duration": 90
}
```

Send `amount_from` of `token_from` from your wallet to `deposit_address` to start the swap. Track progress with **Check Exchange Status** below.

::: tip Partner exchanges are private
Partner exchanges (identified by `hash`) are only accessible by passing the hash as the ID with your `api-key` header. They cannot be queried by normal transaction ID.
:::

::: warning Deposit window
The deposit must match `amount_from` exactly and arrive within ~6 minutes. After timeout you can retry with `?bump=true` on the status endpoint.
:::

***

## 6. Check Exchange Status {#check-exchange-status}

GET `/check/:txId`&#x20;

Get the current state of a single exchange or invoice.

| Query  | Type    | Description                                     |
| ------ | ------- | ----------------------------------------------- |
| `bump` | boolean | If `true`, retries a stalled/timed out exchange |

```bash
curl https://api.p3p.xyz/check/ex_8f4c2a... \
  -H "api-key: YOUR_P3P_API_KEY"
```

```json
{
  "id": "ex_8f4c2a...",
  "created_at": "2026-05-24T10:30:00Z",
  "status": "exchanging",
  "type": "internal",
  "invoice": false,
  "chain_from": "eth",
  "token_from": "eth",
  "amount_from": "0.1",
  "chain_to": "ton",
  "token_to": "ton",
  "amount_to": "342.18",
  "amount_to_unit": 342.18,
  "wallet_to": "UQAbc...XYZ",
  "deposit_address": "0xDepositAddressGeneratedForYou",
  "checkpoint": 3,
  "checkpoints": 5
}
```

### Status values

| Status       | Meaning                                                                 |
| ------------ | ----------------------------------------------------------------------- |
| `new`        | Waiting for the user deposit                                            |
| `deposited`  | Deposit detected, preparing the swap                                    |
| `processing` | Swap submitted to the liquidity source, awaiting confirmation           |
| `exchanging` | Swap confirmed, funds are being exchanged                               |
| `complete`   | Done — recipient has received the funds                                 |
| `timeout`    | Deposit window expired; call with `?bump=true` to reset and retry       |
| `error`      | Exchange encountered an error; call with `?bump=true` to retry          |
| `expired`    | Exchange has expired and can no longer be retried                       |

### Bump retry

If a trade times out (no deposit detected within the deposit window), call the endpoint again with `?bump=true` to reset the window:

```bash
curl "https://api.p3p.xyz/check/ex_8f4c2a...?bump=true" \
  -H "api-key: YOUR_P3P_API_KEY"
```

***

**Partner exchanges** (created with `api-key` header) can be queried by passing the `hash` as the ID. If an `api-key` header is present, the system automatically tries to match it as a `hash` first:

```bash
# Using partner api-key — looks up by hash
curl https://api.p3p.xyz/check/A7K2M9X5B3C1D8F4 \
  -H "api-key: YOUR_PARTNER_API_KEY"
```

```json
{
  "hash": "A7K2M9X5B3C1D8F4",
  "created_at": "2026-05-24T10:30:00Z",
  "status": "complete",
  "type": "internal",
  "invoice": false,
  "chain_from": "eth",
  "token_from": "eth",
  "amount_from": "0.1",
  "chain_to": "ton",
  "token_to": "ton",
  "amount_to": "342.18",
  "amount_to_unit": 342.18,
  "wallet_to": "UQAbc...XYZ",
  "deposit_address": "0xDepositAddressGeneratedForYou",
  "checkpoint": 5,
  "checkpoints": 5
}
```

::: tip Hash format
By default, hashes are 40 alphanumeric characters (a-z, A-Z, 0-9). Partners can customize the format via the Partner Dashboard.
:::

***

## 7. Check Multiple Exchanges {#check-multiple-exchanges}

POST `/check`&#x20;

Check several trades in one call.

**Body**

| Field    | Type     | Required | Description           |
| -------- | -------- | -------- | --------------------- |
| `hashes` | string\[] | yes      | Array of exchange IDs hashes |

```bash
curl -X POST https://api.p3p.xyz/check \
  -H "Content-Type: application/json" \
  -H "api-key: YOUR_P3P_API_KEY" \
  -d '{ "hashes": ["ex_8f4c2a...", "ex_aa11bb..."] }'
```

Returns an array of minified exchange status objects:

```json
[
  {
    "hash": "ex_8f4c2a...",
    "status": "complete",
    "type": "crypto",
    "invoice": false,
    "chain_from": "eth",
    "token_from": "eth",
    "amount_from": "0.1",
    "chain_to": "ton",
    "token_to": "ton",
    "amount_to": "342.18",
    "checkpoint": 4,
    "checkpoints": 4
  },
  {
    "hash": "A7K2M9X5B3C1D8F4",
    "status": "exchanging",
    "type": "crypto",
    "invoice": false,
    "chain_from": "ton",
    "token_from": "usdt",
    "amount_from": "100",
    "chain_to": "eth",
    "token_to": "usdc",
    "amount_to": "99.5",
    "checkpoint": 2,
    "checkpoints": 4
  }
]
```
