Developer reference
API reference
Versioned JSON at /api/v1. No API keys. On Tor, call the same paths on your onion host (e.g. http://…onion/api/v1/…).
Overview
- Base path
/api/v1 - Format Request and response bodies use
application/jsonunless noted. -
Rate limit
30requests per minute per client on/api/v1(salted IP hash; window aligns with60s rotation).
Quickstart
Quote a pair, create a swap with the route you want, then poll with your swap id and private key. Field names match between GET /quote and POST /swap.
-
1. Quote
curl -sS 'https://drifty.trade/api/v1/quote?from=ltc&to=xmr&amount=1'Pick
route=privacyorroute=valuefrom theroutesarray. Same-coin refresh usesfrom=to(privacy by default). -
2. Create
curl -sS -X POST 'https://drifty.trade/api/v1/swap' \ -H 'Content-Type: application/json' \ -d '{"from":"ltc","to":"xmr","amount":"1","route":"value", "destination":"YOUR_XMR_ADDRESS"}'Save
swap_id,private_key, anddeposit_addressfrom the response. Optional:timing=private, splitdestinationarrays. See POST /swap. -
3. Poll
curl -sS -H 'Authorization: Bearer YOUR_PRIVATE_KEY' \ 'https://drifty.trade/api/v1/swap/SWAP_ID'Bearer is your 32-character
private_key;swap_idgoes in the URL. Without Bearer you get404. Legacy 64-character combined keys are still accepted as Bearer. See GET /swap/:id.
Reference
Discovery
GET
/api/v1/status
System status
#
Deployment health, warrant canary, and which route backends are currently reachable.
curl -sS 'https://drifty.trade/api/v1/status'
Response body
{
"system_status": "operational",
"canary_updated": "2026-01-01T00:00:00.000Z",
"canary_signature": "-----BEGIN PGP SIGNATURE-----\n...\n-----END PGP SIGNATURE-----",
"canary_signature_configured": true,
"readiness": {
"thor": true,
"maya": true,
"chainflip": false,
"privacy_exchanges": true
}
}
Response (200)
| Field | Type | Description |
|---|---|---|
system_status |
string | "operational" when at least one readiness backend is available; otherwise "degraded". |
canary_updated |
string | ISO 8601 timestamp from CANARY_UPDATED_AT. |
canary_signature |
string | PGP block from env (canary text). |
canary_signature_configured |
boolean | False when the deployment still uses the built-in placeholder canary signature. |
readiness.thor |
boolean | THORChain node reachable and trading. |
readiness.maya |
boolean | Maya Protocol node reachable and trading. |
readiness.chainflip |
boolean | Chainflip broker reachable when enabled. |
readiness.privacy_exchanges |
boolean | Privacy aggregator quotes available when mixing is enabled. |
GET
/api/v1/coins
Supported coins
#
Coins available for routing. Any coin can be traded to any other coin via smart routing.
curl -sS 'https://drifty.trade/api/v1/coins'
Response body
{
"coins": [
{
"ticker": "btc",
"name": "Bitcoin",
"network": "btc",
"confirmations_required": 1
}
]
}
Response (200)
| Field | Type | Description |
|---|---|---|
coins |
object[] | Each item includes ticker, name, network, confirmations_required. |
GET
/api/v1/quote
Quote
#
Live estimates for a pair. Returns both privacy and value routes (mirrors the site quote page).
curl -sS 'https://drifty.trade/api/v1/quote?from=ltc&to=xmr&amount=1'
Response body
{
"from": "ltc",
"to": "xmr",
"amount": 1,
"type": "floating",
"side": "send",
"routes": [
{
"route_category": "privacy",
"available": true,
"estimated_receive_amount": 0.39,
"estimated_receive_usd": "$41.20",
"network_fees_pct": "1.40",
"network_fees_usd": "$0.57",
"drifty_fee_pct": "1.10",
"drifty_fee_usd": "$0.48",
"estimated_fee_pct": "2.50",
"estimated_fee_usd": "$1.05",
"typical_time": "~30 min"
},
{
"route_category": "value",
"available": true,
"estimated_receive_amount": 0.42,
"estimated_receive_usd": "$44.35",
"network_fees_pct": "0.50",
"network_fees_usd": "$0.22",
"drifty_fee_pct": "1.10",
"drifty_fee_usd": "$0.48",
"estimated_fee_pct": "1.60",
"estimated_fee_usd": "$0.70",
"typical_time": "~5 min"
}
]
}
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
from |
string | Yes | Source ticker (e.g. btc, ltc). |
to |
string | Yes | Destination ticker. |
amount |
string | Yes | Decimal amount. Send units when side=send (default); destination units when side=receive. |
type |
"floating" | "fixed" | No | Quote type. Defaults to floating. |
side |
"send" | "receive" | No | Whether amount is send-side or receive-side. Defaults to send. |
Response (200)
| Field | Type | Description |
|---|---|---|
from |
string | Normalized source ticker. |
to |
string | Normalized destination ticker. |
amount |
number | Echo of the requested amount. |
type |
string | floating or fixed. |
side |
string | send or receive. |
routes |
object[] | Privacy and value route cards. Each available route includes estimated_receive_amount, estimated_receive_usd, network_fees_pct, network_fees_usd, drifty_fee_pct, drifty_fee_usd, estimated_fee_pct (total), estimated_fee_usd, and typical_time. |
400 invalid_request | invalid_amount · 404 unsupported_pair · 502 route_unavailable
Swap
POST
/api/v1/swap
Create swap
#
Creates a swap or privacy session and returns deposit instructions. Use route=privacy or from===to for privacy routing. Returns a one-time private_key (32 chars) alongside swap_id.
curl -sS -X POST 'https://drifty.trade/api/v1/swap' \
-H 'Content-Type: application/json' \
-d '{"from":"ltc","to":"xmr","amount":"1","route":"value","destination":"YOUR_XMR_ADDRESS"}'
Response body
{
"swap_id": "01arz3ndektsv4rrffq69g2f85vw",
"private_key": "9f2c4ab0471deee4b7f91f3ec4f67c9a",
"status": "waiting",
"from": "ltc",
"to": "xmr",
"route": "value",
"type": "floating",
"side": "send",
"deposit_address": "ltc1q...",
"deposit_amount": 1,
"destination": "4AdUnd...",
"estimated_receive": 0.41,
"fees": { "...": "..." },
"reserve_execution_mode": "reserve",
"service_fee_waived": false,
"expires_at": "2026-04-23T12:00:00.000Z"
}
Request body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | Yes | Source ticker. May equal to for same-coin privacy refresh. |
to |
string | Yes | Destination ticker. May equal from for same-coin privacy refresh. |
amount |
string | Yes | Decimal amount. Send units when side=send (default); destination units when side=receive. |
type |
"floating" | "fixed" | No | Quote type. Defaults to floating. Direct value swaps only. |
side |
"send" | "receive" | No | Whether amount is send-side or receive-side. Defaults to send. Direct value swaps only. |
destination |
string | object[] | Yes | Receive address or split. String = 100% payout. Array with one entry = 100%. Array with multiple entries = split payout on any route: each row is an address string or {address, percentage} summing to 100. |
refund_address |
string | No | Refund address for `from` asset if inbound fails. |
memo |
string | No | Destination memo when the receive asset requires one. |
route |
"privacy" | "value" | No | Required for cross-asset swaps. Pick from GET /quote routes. Same-coin refresh (from===to) defaults to privacy. |
timing |
"fast" | "private" | No | Payout timing obfuscation. Defaults to fast. private timing uses the mixing executor on any route. |
Response (201)
| Field | Type | Description |
|---|---|---|
swap_id |
string | 32-character hex swap id (routing). |
private_key |
string | 32-character hex private key (unlock status and encrypted fields). |
status |
"waiting" | Initial API status (awaiting deposit). |
from |
string | Source ticker. |
to |
string | Destination ticker. |
route |
string | privacy | value. |
type |
string | floating or fixed (value route). |
side |
string | send or receive (value route). |
timing |
string | fast or private. |
deposit_address |
string | Inbound deposit address. |
deposit_amount |
number | Requested send amount. |
destination |
string | object[] | Receive address, or masked split rows when mixing executed. |
estimated_receive |
number | Expected output amount. |
fees |
object | Fee breakdown when available. |
reserve_execution_mode |
"reserve" | "direct_routed" | null | XMR reserve decision for custody/reserve paths. |
service_fee_waived |
boolean | True when reserve is disabled and the service fee does not apply. |
reserve_payout_delayed |
boolean | True when high reserve traffic may slow payout; check status message. |
expires_at |
string | ISO 8601 session expiry. |
400 invalid_request | invalid_amount | invalid_address · 404 unsupported_pair · 502 route_unavailable
GET
/api/v1/swap/:swap_id
Retrieve swap
#
Poll status by swap id. Requires Authorization: Bearer <private_key> (32 chars from POST /swap). Returns 404 without a valid Bearer. Legacy 64-char combined Bearer tokens are still accepted.
curl -sS 'https://drifty.trade/api/v1/swap/01arz3ndektsv4rrffq69g2f85vw' \
-H 'Authorization: Bearer YOUR_32_CHAR_PRIVATE_KEY'
Response body
{
"swap_id": "01arz3ndektsv4rrffq69g2f85vw",
"status": "waiting",
"from": "ltc",
"to": "xmr",
"route": "value",
"deposit_address": "ltc1q...",
"deposit_amount": 1,
"destination": "4AdUnd...",
"estimated_receive": 0.41,
"expires_at": "2026-04-23T12:00:00.000Z"
}
Response (200)
| Field | Type | Description |
|---|---|---|
swap_id |
string | Session id. |
from |
string | Source ticker. |
to |
string | Destination ticker. |
status |
string | waiting | confirming | exchanging | sending | completed | failed | flagged_kyc, or mixing statuses (awaiting_deposit, mixing_leg1, cooling_off, mixing_leg2) when applicable. |
route |
string | privacy | value when unlocked. |
type |
string | floating or fixed on direct value swaps when unlocked. |
side |
string | send or receive on direct value swaps when unlocked. |
timing |
string | fast | private when unlocked. |
deposit_address |
string | null | Inbound deposit address when unlocked. |
deposit_amount |
number | Declared send amount when unlocked. |
received_amount |
number | 0 while waiting; otherwise aligned with deposit tracking when unlocked. |
destination |
string | object[] | Receive address or split rows when unlocked. |
memo |
string | null | Destination memo when applicable and unlocked. |
estimated_receive |
number | null | Expected output amount when unlocked. |
tx_out_hash |
string | null | Outbound tx id when known and unlocked. |
execution_status.last_poll_at |
string | null | Last execution status poll attempt when unlocked. |
execution_status.unreachable_since |
string | null | Start of the current status outage window, if any, when unlocked. |
execution_status.last_error |
string | null | Most recent status polling error, if any, when unlocked. |
failure_reason |
string | null | Terminal failure reason when status is failed or flagged_kyc and unlocked. |
updated_at |
string | ISO 8601 last update when unlocked. |
expires_at |
string | ISO 8601 session expiry when unlocked. |
404 not_found - missing Bearer, invalid private key, or unknown/expired swap_id.
POST
/api/v1/swap/:swap_id/cancel
Cancel pending privacy swap
#
Cancels privacy sessions only while status is awaiting_deposit (mixing_leg1_pending internally). Requires Bearer private_key.
curl -sS -X POST -H 'Authorization: Bearer YOUR_PRIVATE_KEY' 'https://drifty.trade/api/v1/swap/01arz3ndektsv4rrffq69g2f85vw/cancel'
Response body
{ "ok": true }
Response (200)
| Field | Type | Description |
|---|---|---|
ok |
boolean | True when cancellation succeeds. |
404 not_found invalid/missing bearer key · 409 conflict once execution has started.