EN

Documentation

Partner Exchange API

REST JSON API for embedding crypto exchange into your site, bot, or service: asset catalog → quote → create exchange → track status.

Base URL https://snapex.pro/api/v1/partner

1. Overview

The Partner Exchange API lets you run crypto exchanges from your application with plain HTTP requests. You send JSON — the API returns the rate, a deposit address, and the exchange status. This section explains the overall flow; each step is covered in detail below.

How an exchange works

Every exchange follows the same four-step flow:

  1. Catalog (GET /assets). Find out which assets are available and within what limits. The catalog provides the short asset codes — usdt, btc, eth, xmr, etc.
  2. Quote (POST /quotes). You ask: "how much BTC will the client get for 20 USDT?" The API answers with the rate and exact amounts. A quote is non-binding and stays valid for 2 minutes.
  3. Create exchange (POST /exchanges). You confirm the quote — the API opens an order and returns a deposit address the client must send funds to.
  4. Status (GET /exchanges/{quote_id}). You poll the API to learn whether the deposit arrived and the payout was sent.

What you need to get started

  1. A partner cabinet account.
  2. An approved API access request (submitted in the cabinet, reviewed by an administrator).
  3. An API key starting with spx_… — issued in the cabinet after approval. The key is shown only once when issued or reissued: store it somewhere safe right away.

Methods

Method Path Success HTTP code Purpose
GET /assets 200 Asset catalog and limits
POST /quotes 201 Quote (rate and amounts)
POST /exchanges 201 Create exchange, obtain a deposit address
GET /exchanges/{quote_id} 200 Current quote or exchange status

Data format

  • All requests and responses are JSON, UTF-8.
  • All monetary amounts are strings: "20", "0.000312". The decimal separator is a dot. Strings are intentional: floating-point numbers lose precision on crypto amounts.
  • Dates use ISO-8601 with a timezone, e.g. 2026-07-27T13:02:00+00:00.

Headers for every request

X-API-Key: spx_your_key
Content-Type: application/json   (POST requests only)
Accept: application/json

Key rules

  • A quote is valid for 2 minutes (the expires_at field) — the exchange must be created before it expires.
  • At most 1 request per IP address every 7 seconds across all methods; exceeding this returns HTTP 429 (see "Errors and limits").
  • Retrying exchange creation with the same parameters is safe: no duplicate is created — the same exchange is returned.

2. Authentication

Every API request must include the X-API-Key header with your key. No tokens, signatures, or sessions — just this one header.

GET https://snapex.pro/api/v1/partner/assets
X-API-Key: spx_your_key
Accept: application/json

Where to get the key

Partner cabinet → "API" tab → "Issue key". The key starts with spx_ and is shown once. Reissuing immediately invalidates the old key.

Authentication errors

HTTP error Cause What to do
401 unauthorized X-API-Key header missing or key invalid Check that the header is sent and the key was copied in full
403 api_access_pending Access request still under review Wait for admin approval
403 api_not_approved API access not approved Contact support

3. Asset catalog — GET /assets

The directory of available assets and send-amount limits. Integration starts here: it provides the asset codes for quotes and the allowed amount ranges. Success response — HTTP 200.

The API accepts only the short codes from the code field of this catalog (usdt, btc, eth, xmr, etc.). Raw internal blockchain identifiers are not accepted. The catalog changes rarely — you can cache it on your side for 5–10 minutes.

Request example

GET https://snapex.pro/api/v1/partner/assets
X-API-Key: spx_your_key
Accept: application/json

Response example

{
  "assets": [
    {
      "code": "usdt",
      "network": "TRON",
      "symbol": "USDT",
      "name": "USDT TRON",
      "min_amount": "10",
      "max_amount": "5000",
      "min_usd": "10",
      "max_usd": "5000"
    },
    {
      "code": "btc",
      "network": "Bitcoin",
      "symbol": "BTC",
      "name": "BTC",
      "min_amount": "0.000085",
      "max_amount": "0.0425",
      "min_usd": "10",
      "max_usd": "5000"
    }
  ]
}

Response fields

Field Description
assets[].code Short asset code. This is exactly what you pass as from_asset_id and to_asset_id
assets[].network Blockchain network (TRON, Bitcoin, Ethereum, etc.)
assets[].symbol Asset ticker (USDT, BTC…)
assets[].name Human-readable name
assets[].min_amount / max_amount Minimum and maximum send amount in asset units (converted from the USD limits at the current rate)
assets[].min_usd / max_usd The same limits in US dollars

USD limits by route type

Limits depend on whether Monero (XMR) is part of the exchange. The check applies to the USD value of the amount the client sends.

Route Min USD Max USD
Regular exchange (TOKEN ↔ TOKEN) $10 $7000
Sending XMR (XMR → TOKEN) $10 $1000
Receiving XMR (TOKEN → XMR) $10 $1000

Current catalog

The table below shows the same data GET /assets returns, for quick reference.

API code Network Asset Min send Max send Min USD Max USD
aave APTOS AAVE 0.05951319 41.65922752 $10 $7000
btc_aptos APTOS BTC 0.00012061 0.08442686 $10 $7000
doge APTOS DOGE 116.6997316 81689.81211343 $10 $7000
eth APTOS ETH 0.00399422 2.79595146 $10 $7000
link APTOS LINK 0.77041603 539.29121726 $10 $7000
sol APTOS SOL 0.09101666 63.71165923 $10 $7000
uni APTOS UNI 1.31926122 923.4828496 $10 $7000
xrp APTOS XRP 7.142858 5000 $10 $7000
zec APTOS ZEC 0.0081793 5.72550303 $10 $7000
avax Avalanche AVAX 0.96711799 676.98259188 $10 $7000
cfi Base CFI 15268.34109475 10687838.76631804 $10 $7000
btc Bitcoin BTC 0.00012061 0.08442686 $10 $7000
aster BNB Chain ASTER 14.09715478 9868.00833988 $10 $7000
aurora BNB Chain AURORA 162.22705299 113558.93708835 $10 $7000
bnb BNB Chain BNB 0.01337614 9.36329588 $10 $7000
usdc HYPERCORE USDC 10.00292086 7002.04459702 $10 $7000
mon Monad MON 399.36485015 279555.39509963 $10 $7000
xmr Monero XMR 0.01934563 1.93456265 $10 $1000
op Optimism OP 72.03676757 50425.73729632 $10 $7000
usdt0 Optimism USDT0 10.009349 7006.544112 $10 $7000
pol Polygon POL 98.27526903 68792.68831998 $10 $7000
rhea Solana RHEA 117.61246693 82328.72684505 $10 $7000
strk Solana STRK 97.88662771 68520.63939545 $10 $7000
zec_solana Solana ZEC 0.0081793 5.72550303 $10 $7000
xlm Stellar XLM 51.0394178 35727.5924196 $10 $7000
gram TON GRAM 6.84931507 4794.52054795 $10 $7000
usdt TRON USDT 10.008398 7005.877932 $10 $7000
okb X Layer OKB 0.07932102 55.5247085 $10 $7000

4. Quote — POST /quotes

Calculates the rate and exact exchange amounts. Creates nothing and commits you to nothing: no deposit address is allocated, no funds are reserved. Success response — HTTP 201. A quote is valid for 2 minutes.

Two modes: side=send and side=receive

The side parameter defines which of the two amounts is fixed:
side=send — "the client sends exactly X, how much will they get?" The amount is given in the send (from) asset.
side=receive — "the client wants to receive exactly Y, how much must they send?" The amount is given in the receive (to) asset.

Mode amount — in which asset amount_usd
side=send In the from_asset_id asset (what the client sends) Allowed: the send amount in USD instead of amount
side=receive In the to_asset_id asset (what the client receives) Not allowed — amount only

Pass either amount or amount_usd — one of the two. Sending both returns a 422 error.

Request example

POST https://snapex.pro/api/v1/partner/quotes
Content-Type: application/json
X-API-Key: spx_your_key

{
  "from_asset_id": "usdt",
  "to_asset_id": "btc",
  "side": "send",
  "amount": "20",
  "recipient_address": "bc1qexampleaddress"
}

Request parameters

Field Required Description
from_asset_id Yes Code of the asset the client sends (from the GET /assets catalog)
to_asset_id Yes Code of the asset the client receives. Must differ from from_asset_id
side Yes send or receive — see the table above
amount Yes, unless amount_usd is used Amount as a string, e.g. "20" or "0.0005". For send — in the from asset, for receive — in the to asset
amount_usd No side=send only: the send amount in US dollars, e.g. "100". Mutually exclusive with amount
recipient_address Yes The client wallet address on the receive (to) asset network. Needed already at the quote stage — it validates the route. Alias: recipient

Response example

{
  "quote_id": "pq_abc123",
  "status": "quoted",
  "side": "send",
  "from_symbol": "USDT",
  "to_symbol": "BTC",
  "from_network": "TRON",
  "to_network": "Bitcoin",
  "request_amount": "20",
  "send_amount": "20",
  "receive_amount": "0.000312",
  "amount_in_usd": "20",
  "amount_out_usd": "19.85",
  "expires_at": "2026-07-27T13:02:00+00:00"
}

Response fields

Field Description
quote_id Quote identifier (pq_…). Needed to create the exchange and check its status
status quoted — the quote is active, no exchange created yet
side The amount-fixing mode from your request
from_symbol / to_symbol Send and receive asset tickers
from_network / to_network Asset networks
request_amount The amount from your request
send_amount How much the client must send
receive_amount How much the client will receive
amount_in_usd / amount_out_usd USD estimates of the send and receive amounts
request_amount_usd Present only if the request used amount_usd
expires_at Quote expiry moment (ISO-8601). After it, this quote_id can no longer be used to create an exchange

5. Create exchange — POST /exchanges

Turns a quote into a real exchange: an order is opened and a deposit address is returned for the client transfer. Call it before the quote expires (2 minutes). Success response — HTTP 201.

Request example

POST https://snapex.pro/api/v1/partner/exchanges
Content-Type: application/json
X-API-Key: spx_your_key

{
  "quote_id": "pq_abc123",
  "recipient_address": "bc1qexampleaddress"
}

Request parameters

Field Required Description
quote_id Yes Identifier from the POST /quotes response
recipient_address Yes Client payout address. Usually the same one used in the quote. Alias: recipient

What happens on this call

  1. The API finds your quote and checks it has not expired.
  2. The rate is re-checked against the market. If it moved against the quote by more than 2%, no exchange is created and 422 is returned (simply request a new quote).
  3. An order is opened and a deposit address is allocated.
  4. The response includes the deposit block — the address and amount the client must transfer.

Response example

{
  "quote_id": "pq_abc123",
  "status": "awaiting_deposit",
  "side": "send",
  "from_symbol": "USDT",
  "to_symbol": "BTC",
  "from_network": "TRON",
  "to_network": "Bitcoin",
  "request_amount": "20",
  "send_amount": "20",
  "receive_amount": "0.000312",
  "amount_in_usd": "20",
  "amount_out_usd": "19.85",
  "expires_at": "2026-07-27T13:02:00+00:00",
  "deposit": {
    "asset": "USDT",
    "amount": "20",
    "address": "TXyz…",
    "amount_usd": "20"
  },
  "exchange": {
    "public_id": "ex_…",
    "status": "awaiting_deposit",
    "recipient_address": "bc1qexampleaddress"
  }
}

New fields compared to the quote

Field Description
status Usually awaiting_deposit — waiting for the client transfer. quoting means the deposit address is still being prepared: poll the status again shortly
deposit.asset The asset the client must transfer
deposit.amount The exact transfer amount
deposit.address The deposit address — show it to the client
deposit.amount_usd USD equivalent (when available)
exchange.public_id Public exchange identifier
exchange.status Order status (matches the top-level status)
exchange.recipient_address Client payout address

Retries (idempotency)

If the connection dropped and you never got a response — just repeat the request with the same quote_id and recipient_address. No duplicate is created: the API returns the already existing exchange. The recipient_address cannot be changed after creation — attempting to do so returns 422.

Possible errors

  • 409 quote_expired — the quote expired (more than 2 minutes passed). Request a new one via POST /quotes.
  • 422 validation_error — invalid parameters; an attempt to change recipient_address on retry; or the rate moved by more than 2% — request a new quote.
  • 404 not_found — the quote_id does not exist or belongs to another partner.
  • 503 upstream_unavailable — temporary liquidity provider failure. Retry later with the same quote (if still valid) or a new one.

6. Status — GET /exchanges/{quote_id}

Returns the current state of a quote or exchange. The response format is identical to the create response. Success response — HTTP 200. Poll at most once every 7 seconds.

Request example

GET https://snapex.pro/api/v1/partner/exchanges/pq_abc123
X-API-Key: spx_your_key
Accept: application/json

status values

Value Meaning What to do
quoted Only a quote exists, no exchange created Create the exchange before expires_at or request a new quote
quoting The exchange is being created, deposit address being prepared Poll the status again in a few seconds
awaiting_deposit Waiting for the client transfer to the deposit address Show the client the address and amount from the deposit block
processing Deposit received, exchange in progress Keep polling
completed Exchange finished, funds sent to the client Terminal status — stop polling
error Exchange failed Terminal status. Contact support with the exchange.public_id
cancelled Exchange cancelled Terminal status
expired The quote expired, no exchange was created Terminal status. Request a new quote

Terminal statuses: completed, error, cancelled, expired. The state no longer changes after them — further polling is unnecessary.

When status=completed, the exchange block may include partner_api_earning_usd — your earnings on the deal in USD.

Response example

{
  "quote_id": "pq_abc123",
  "status": "completed",
  "side": "send",
  "from_symbol": "USDT",
  "to_symbol": "BTC",
  "from_network": "TRON",
  "to_network": "Bitcoin",
  "request_amount": "20",
  "send_amount": "20",
  "receive_amount": "0.000312",
  "amount_in_usd": "20",
  "amount_out_usd": "19.85",
  "expires_at": "2026-07-27T13:02:00+00:00",
  "deposit": {
    "asset": "USDT",
    "amount": "20",
    "address": "TXyz…",
    "amount_usd": "20"
  },
  "exchange": {
    "public_id": "ex_…",
    "status": "completed",
    "recipient_address": "bc1qexampleaddress",
    "partner_api_earning_usd": "0.20"
  }
}

7. Errors and limits

All errors share a single JSON format. The HTTP status code mirrors the meaning of the error field — rely on either one.

{
  "ok": false,
  "error": "validation_error",
  "message": "Human-readable explanation in English"
}

Error reference

HTTP error Cause What to do
401 unauthorized Missing or invalid X-API-Key Check the header and the key
403 api_access_pending Access request under review Wait for approval
403 api_not_approved API access not approved Contact support
404 not_found Unknown or foreign quote_id Check the identifier
409 quote_expired The quote is older than 2 minutes Request a new quote
422 validation_error Invalid parameters, limit violation, or rate move > 2% Read the message, fix the request, or get a fresh quote
429 rate_limited Request rate exceeded Wait and retry
503 upstream_unavailable Temporary liquidity provider failure Retry later

Rate limits

Scope Limit
All methods, per IP address 1 request every 7 seconds
POST /quotes, per partner 15 requests per minute
POST /exchanges, per partner 10 requests per minute
GET /assets and GET /exchanges/{quote_id}, per partner 120 requests per minute

8. Example: an exchange from start to finish

Full scenario: the client sends 20 USDT (TRON network) and receives BTC at their Bitcoin address. Replace YOUR_KEY with your API key.

Step 1. Request a quote

curl -sS -X POST 'https://snapex.pro/api/v1/partner/quotes' \
  -H 'X-API-Key: YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "from_asset_id": "usdt",
    "to_asset_id": "btc",
    "side": "send",
    "amount": "20",
    "recipient_address": "bc1qexample"
  }'

The response contains a quote_id (pq_…) and the amounts. Show the client receive_amount — that is how much BTC they will get. You have 2 minutes for the next step.

Step 2. Create the exchange

curl -sS -X POST 'https://snapex.pro/api/v1/partner/exchanges' \
  -H 'X-API-Key: YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "quote_id": "pq_FROM_STEP_1",
    "recipient_address": "bc1qexample"
  }'

The response now includes the deposit block with an address and amount. Show the client deposit.address and deposit.amount — they must transfer exactly that amount to that address.

Step 3. Track the status

curl -sS 'https://snapex.pro/api/v1/partner/exchanges/pq_FROM_STEP_1' \
  -H 'X-API-Key: YOUR_KEY' \
  -H 'Accept: application/json'

Repeat the request with a 7–10 second pause. Once the client transfers the funds, the status changes to processing, then to completed — the payout has been sent. Terminal statuses: completed, error, cancelled, expired.

The same scenario in Python

import time
import requests

API = "https://snapex.pro/api/v1/partner"
HEADERS = {
    "X-API-Key": "YOUR_KEY",
    "Content-Type": "application/json",
    "Accept": "application/json",
}

# Step 1. Quote: the client sends 20 USDT, receives BTC
quote = requests.post(f"{API}/quotes", headers=HEADERS, json={
    "from_asset_id": "usdt",
    "to_asset_id": "btc",
    "side": "send",
    "amount": "20",
    "recipient_address": "bc1qexample",
}).json()
print("Client receives:", quote["receive_amount"], quote["to_symbol"])

# Step 2. Create the exchange (within 2 minutes of the quote)
exchange = requests.post(f"{API}/exchanges", headers=HEADERS, json={
    "quote_id": quote["quote_id"],
    "recipient_address": "bc1qexample",
}).json()
deposit = exchange["deposit"]
print("Client must transfer:", deposit["amount"], deposit["asset"])
print("To address:", deposit["address"])

# Step 3. Poll the status until terminal
while True:
    time.sleep(10)  # at most 1 request every 7 seconds
    state = requests.get(
        f"{API}/exchanges/{quote['quote_id']}", headers=HEADERS
    ).json()
    print("Status:", state["status"])
    if state["status"] in ("completed", "error", "cancelled", "expired"):
        break

Common beginner mistakes

  • Sending the amount as a number instead of a string. Correct: "amount": "20", not "amount": 20.
  • With side=receive, giving the amount in the send asset. For receive, amount is in the receive (to) asset.
  • Creating the exchange more than 2 minutes after the quote — you get 409 quote_expired. Request the quote right before creating.
  • Sending requests more often than once every 7 seconds — you get 429. Add a pause between requests.