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/json unless noted.
  • Rate limit 30 requests per minute per client on /api/v1 (salted IP hash; window aligns with 60s 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. 1. Quote

    curl -sS 'https://drifty.trade/api/v1/quote?from=ltc&to=xmr&amount=1'

    Pick route=privacy or route=value from the routes array. Same-coin refresh uses from=to (privacy by default).

  2. 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, and deposit_address from the response. Optional: timing=private, split destination arrays. See POST /swap.

  3. 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_id goes in the URL. Without Bearer you get 404. 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.

← Back home