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.
api-key: YOUR_P3P_API_KEYPartner key = your fee
If you authenticate with your partner key (from the Partner Dashboard), 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.
Endpoints
1. Get Chains
GET /chains api-key required
Returns every chain currently enabled on p3p.
curl https://api.p3p.xyz/chains \
-H "api-key: YOUR_P3P_API_KEY"const chains = await fetch("https://api.p3p.xyz/chains", {
headers: { "api-key": "YOUR_P3P_API_KEY" },
}).then((r) => r.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 api-key required
Returns enabled tokens grouped by chain.
curl https://api.p3p.xyz/tokens \
-H "api-key: YOUR_P3P_API_KEY"{
"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 api-key required
Returns live market reference rates for every supported asset, sourced from on chain oracles.
curl https://api.p3p.xyz/rates \
-H "api-key: YOUR_P3P_API_KEY"{
"btc": 98234.56,
"eth": 3421.8,
"ton": 5.23,
"usdt": 1.0,
"usdc": 1.0,
"sol": 142.35
}4. Quote Exchange Rate
POST /exchange/rate api-key required
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. |
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 }
}'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());{
"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
POST /exchange/create api-key required
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. |
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).
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.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{
"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:
{
"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.
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.
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
GET /check/:txId api-key required
Get the current state of a single exchange or invoice.
| Query | Type | Description |
|---|---|---|
bump | boolean | If true, retries a stalled/timed out exchange |
curl https://api.p3p.xyz/check/ex_8f4c2a... \
-H "api-key: YOUR_P3P_API_KEY"{
"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:
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:
# Using partner api-key — looks up by hash
curl https://api.p3p.xyz/check/A7K2M9X5B3C1D8F4 \
-H "api-key: YOUR_PARTNER_API_KEY"{
"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
}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
POST /check api-key required
Check several trades in one call.
Body
| Field | Type | Required | Description |
|---|---|---|---|
hashes | string[] | yes | Array of exchange IDs hashes |
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:
[
{
"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
}
]