{
  "openapi": "3.0.3",
  "info": {
    "title": "dexr.pro API",
    "version": "2.8.0",
    "description": "Cross-chain swap router: one request fans out to seven providers — THORChain, NEAR Intents, ETZ Swap, Chainflip, Symbiosis, Mayan, CCE.CASH — quoted in parallel over Tor, ranked on net received after fees.\n\n**No keys, no accounts.** Every endpoint is open. Rate limits are per-endpoint *global* sliding-window counters (requests per 60 s), keyed on nothing — no IP or client identifier is read or stored; over Tor an IP is just a shared exit node. Each operation documents its bucket as `x-rate-limit`. A `429` means the shared bucket is momentarily exhausted — back off a few seconds.\n\n**House rules:** (1) nothing about who you are is persisted — an anonymized aggregate counter and a 30-day deletable per-swap receipt are the only writes, both encrypted at rest; (2) the same API answers identically on clearnet and on the onion service; (3) status is always reconstructed from the chain or the provider, never from a database of your history.",
    "contact": {
      "name": "dexr.pro",
      "url": "https://dexr.pro/developers"
    }
  },
  "servers": [
    {
      "url": "https://dexr.pro",
      "description": "clearnet"
    },
    {
      "url": "http://5bsl5k7l4xpia2ss5sqdzmqmqzuezudzyht7plgomjuqaxjhkndmffyd.onion",
      "description": "onion service — identical answers, the whole round trip inside Tor"
    }
  ],
  "tags": [
    {
      "name": "Quotes",
      "description": "Quote fan-out and execution instructions"
    },
    {
      "name": "Tracking",
      "description": "Live status, settlement watching, browser-side verification"
    },
    {
      "name": "Receipts",
      "description": "30-day deletable swap receipts for recovery and support"
    },
    {
      "name": "Transparency",
      "description": "Aggregate counters, provider trust profiles, service state"
    },
    {
      "name": "Relay",
      "description": "Narrow EVM JSON-RPC relay for one-time vault payments"
    }
  ],
  "paths": {
    "/api/quote": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Quote a swap across providers",
        "description": "Fans the request out to all providers (or a pinned subset) in parallel and returns the routes ranked on net received. With no `destination`, quotes are priced with ephemeral or address-free destinations — nothing linkable leaves the server (CCE.CASH prices from coin + chain + amount only). Maintenance mode answers `503`.",
        "x-rate-limit": 60,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "from",
                  "to",
                  "amount"
                ],
                "properties": {
                  "from": {
                    "type": "string",
                    "example": "BTC.BTC",
                    "description": "CHAIN.SYMBOL of the asset you pay"
                  },
                  "to": {
                    "type": "string",
                    "example": "XMR.XMR",
                    "description": "CHAIN.SYMBOL of the asset you receive"
                  },
                  "amount": {
                    "type": "string",
                    "example": "0.05",
                    "description": "Human-readable input amount"
                  },
                  "provider": {
                    "type": "string",
                    "example": "cce",
                    "description": "Optional pin: one provider id or comma-separated subset (thorchain, near, etz, chainflip, symbiosis, mayan, cce)"
                  },
                  "destination": {
                    "type": "string",
                    "description": "Optional real receive address — include only when proceeding"
                  },
                  "slippageBps": {
                    "type": "number",
                    "description": "Optional slippage tolerance in basis points"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked quote results (providers that declined or errored are omitted, with reasons)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "provider": {
                            "type": "string",
                            "example": "cce"
                          },
                          "routeId": {
                            "type": "string"
                          },
                          "amountOut": {
                            "type": "string",
                            "description": "Expected output in base units"
                          },
                          "amountOutMin": {
                            "type": "string"
                          },
                          "fees": {
                            "type": "object"
                          },
                          "trust": {
                            "type": "object",
                            "description": "The provider's published trust profile"
                          },
                          "warnings": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "expiresAt": {
                            "type": "number",
                            "description": "ms epoch — execute before this"
                          }
                        }
                      }
                    },
                    "fromDecimals": {
                      "type": "number"
                    },
                    "toDecimals": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad asset id or amount",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted — back off",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Maintenance pause",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/execute": {
      "post": {
        "tags": [
          "Quotes"
        ],
        "summary": "Turn a quoted route into payment instructions",
        "description": "Returns the concrete payload: a deposit address (+ memo / swap id) for transfer routes, or the exact EVM calldata your wallet signs for contract routes. This is the moment the real destination leaves the server — exactly once.",
        "x-rate-limit": 30,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider",
                  "from",
                  "to",
                  "amount",
                  "destination"
                ],
                "properties": {
                  "provider": {
                    "type": "string",
                    "example": "cce"
                  },
                  "from": {
                    "type": "string",
                    "example": "BTC.BTC"
                  },
                  "to": {
                    "type": "string",
                    "example": "XMR.XMR"
                  },
                  "amount": {
                    "type": "string",
                    "description": "Base units"
                  },
                  "destination": {
                    "type": "string",
                    "description": "Your real receive address"
                  },
                  "refundAddress": {
                    "type": "string",
                    "description": "Optional (Chainflip)"
                  },
                  "sender": {
                    "type": "string",
                    "description": "Optional 0x vault address binding (EVM calldata routes)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Execution instructions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "provider": {
                      "type": "string"
                    },
                    "instructions": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "onchain-transfer",
                            "evm-calldata"
                          ]
                        },
                        "chain": {
                          "type": "string"
                        },
                        "amount": {
                          "type": "string"
                        },
                        "depositAddress": {
                          "type": "string"
                        },
                        "memo": {
                          "type": "string"
                        },
                        "swapId": {
                          "type": "string",
                          "description": "Provider order handle — keep it for tracking/recovery (Chainflip channel id, CCE.CASH query code)"
                        },
                        "to": {
                          "type": "string",
                          "description": "Contract address (evm-calldata)"
                        },
                        "data": {
                          "type": "string",
                          "description": "Calldata (evm-calldata)"
                        },
                        "expiresAt": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing/invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Maintenance pause",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/track-status": {
      "post": {
        "tags": [
          "Tracking"
        ],
        "summary": "Poll the live status of an executed swap",
        "description": "Re-checks state with the provider (or the destination chain) on every call. Pass whichever reference the provider issued: `swapId` (Chainflip channel id, CCE.CASH query code), `depositAddress`, `txHash`, or `destinationAddress`+`destinationChain` for providers tracked by payout. Providers without a status API answer `unknown` rather than erroring. Terminal outcomes are counted once, deduped by the provider's own identifier.",
        "x-rate-limit": 240,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider"
                ],
                "properties": {
                  "provider": {
                    "type": "string",
                    "example": "cce"
                  },
                  "swapId": {
                    "type": "string"
                  },
                  "depositAddress": {
                    "type": "string"
                  },
                  "channelId": {
                    "type": "string"
                  },
                  "txHash": {
                    "type": "string"
                  },
                  "destinationAddress": {
                    "type": "string"
                  },
                  "destinationChain": {
                    "type": "string"
                  },
                  "sinceMs": {
                    "type": "number"
                  },
                  "asset": {
                    "type": "string",
                    "description": "Input asset, for outcome counting"
                  },
                  "amount": {
                    "type": "string",
                    "description": "Human input amount, for outcome counting"
                  },
                  "toAsset": {
                    "type": "string",
                    "description": "Output asset — forms the anonymized pair"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "provider": {
                      "type": "string"
                    },
                    "status": {
                      "type": "object",
                      "properties": {
                        "state": {
                          "type": "string",
                          "enum": [
                            "pending_deposit",
                            "processing",
                            "success",
                            "refunded",
                            "failed",
                            "unknown"
                          ]
                        },
                        "detail": {
                          "type": "string"
                        },
                        "settledAsset": {
                          "type": "string"
                        },
                        "settledAmountHuman": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/watch": {
      "post": {
        "tags": [
          "Tracking"
        ],
        "summary": "Register a swap for server-side settlement watching",
        "description": "Lets a swap resolve (and be counted) even after the browser tab closes. The reference is held **in memory only** — never written to disk — and dropped at settlement or after a couple of hours. The watcher re-verifies state independently; a bogus registration simply never goes terminal and ages out.",
        "x-rate-limit": 120,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider"
                ],
                "properties": {
                  "provider": {
                    "type": "string"
                  },
                  "swapId": {
                    "type": "string"
                  },
                  "depositAddress": {
                    "type": "string"
                  },
                  "channelId": {
                    "type": "string"
                  },
                  "txHash": {
                    "type": "string"
                  },
                  "destinationAddress": {
                    "type": "string"
                  },
                  "destinationChain": {
                    "type": "string"
                  },
                  "sinceMs": {
                    "type": "number"
                  },
                  "fromAsset": {
                    "type": "string"
                  },
                  "toAsset": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registration result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "watching": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/verify": {
      "post": {
        "tags": [
          "Tracking"
        ],
        "summary": "Raw observed-tx + vault set for the browser-side audit",
        "description": "Returns the THORChain-observed transaction, the current inbound vault set, and (best-effort) midgard actions. The server checks **nothing** — every verification runs in the caller's browser against this raw data.",
        "x-rate-limit": 120,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "txid"
                ],
                "properties": {
                  "txid": {
                    "type": "string",
                    "description": "The deposit transaction hash (hex)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Raw verification material",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tx": {
                      "type": "object"
                    },
                    "vaults": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "actions": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a transaction hash, or no record of it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/receipt": {
      "post": {
        "tags": [
          "Receipts"
        ],
        "summary": "Store a recoverable swap receipt",
        "description": "Keeps one small nameless record (provider ids, deposit tx, destination, amounts) encrypted at rest for 30 days, so a swap can be recovered from another device or helped with by support. Delete it any time via `/api/receipt/delete`.",
        "x-rate-limit": 120,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider"
                ],
                "properties": {
                  "provider": {
                    "type": "string"
                  },
                  "providerOrderId": {
                    "type": "string"
                  },
                  "depositAddress": {
                    "type": "string"
                  },
                  "txHash": {
                    "type": "string"
                  },
                  "destination": {
                    "type": "string"
                  },
                  "fromAsset": {
                    "type": "string"
                  },
                  "toAsset": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "string"
                  },
                  "expectedOut": {
                    "type": "string"
                  },
                  "expectedOutUsd": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored — keep the delete token; it is shown once",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleteToken": {
                      "type": "string"
                    },
                    "expiresAt": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Receipt store full",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "Fetch a receipt for recovery",
        "description": "By `id`, or by an on-chain reference (`tx` / `ref`) your wallet still has. Answers `410` once deleted or expired.",
        "x-rate-limit": 120,
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Receipt id"
          },
          {
            "name": "tx",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Deposit tx hash or provider order reference"
          }
        ],
        "responses": {
          "200": {
            "description": "The receipt",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "410": {
            "description": "Deleted, expired, or never existed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/receipt/delete": {
      "post": {
        "tags": [
          "Receipts"
        ],
        "summary": "Permanently delete a receipt",
        "description": "Requires the one-time delete token issued at storage. Returns a deletion proof signed by the server's receipt key (see `/api/receipt-key`) — verifiable offline. The anonymized aggregate counters are a separate store and are untouched. Already-gone receipts answer idempotently; a wrong token on a live receipt is a `403`.",
        "x-rate-limit": 30,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "token"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deleted, with signed proof",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "alreadyGone": {
                      "type": "boolean"
                    },
                    "receipt": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "purgedAt": {
                          "type": "number"
                        },
                        "sig": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Delete token does not match",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/receipt-key": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "The receipt-signing public key",
        "description": "Raw 32-byte ed25519 public key (base64) that signs deletion proofs, so anyone can verify a \"purged\" claim offline.",
        "x-rate-limit": 60,
        "responses": {
          "200": {
            "description": "The public key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pubkey": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/stats": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "Aggregate swap counters + anonymized recent feed",
        "description": "Totals and a recent-swaps list built from aggregates only: asset, rounded amount, outcome, dollar value, time. No addresses, no txids, no IPs. Never maintenance-gated — it is a transparency endpoint.",
        "x-rate-limit": 120,
        "responses": {
          "200": {
            "description": "The aggregate snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/providers": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "Provider trust profiles",
        "description": "The published trust profile of every public provider — custody model, KYC posture, freeze risk, logging, Tor friendliness, incidents. This is what the reputation badges are computed from.",
        "x-rate-limit": 240,
        "responses": {
          "200": {
            "description": "The provider list with trust profiles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "providers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "role": {
                            "type": "string"
                          },
                          "enabled": {
                            "type": "boolean"
                          },
                          "trust": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/assets": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "The live asset universe",
        "description": "THORChain pools ∪ NEAR 1Click tokens ∪ Chainflip's static set, decimals-verified, plus Monero (reachable only via CCE.CASH). Icons come from the shipped pipeline map with a glyph fallback.",
        "x-rate-limit": 60,
        "responses": {
          "200": {
            "description": "The asset list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "assets": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Maintenance pause",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/routes": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "The supported route matrix",
        "description": "Which chains and assets can move, used by the app to offer only quotable pairs.",
        "x-rate-limit": 60,
        "responses": {
          "200": {
            "description": "The route matrix",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Maintenance pause",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "Provider health",
        "description": "Per-provider liveness, checked live.",
        "x-rate-limit": 120,
        "responses": {
          "200": {
            "description": "Health report",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "Service state, including the Tor self-check",
        "description": "Server mode, maintenance flag, the Tor process state, the current exit IP as seen by check.torproject.org, and the provider trust list.",
        "x-rate-limit": 120,
        "responses": {
          "200": {
            "description": "Service state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/onion": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "The onion hostname",
        "description": "So clients can discover the onion endpoint from the clearnet one and pin it.",
        "x-rate-limit": 60,
        "responses": {
          "200": {
            "description": "The hostname",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/vaults": {
      "get": {
        "tags": [
          "Transparency"
        ],
        "summary": "Current THORChain inbound vault addresses",
        "description": "The set the browser-side audit checks a deposit address against — so \"am I really paying the network vault?\" is answerable without trusting us.",
        "x-rate-limit": 60,
        "responses": {
          "200": {
            "description": "Inbound addresses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vaults": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/rpc": {
      "post": {
        "tags": [
          "Relay"
        ],
        "summary": "Narrow EVM JSON-RPC relay",
        "description": "Exists for browser-side one-time vault payments: the browser generates the vault wallet, signs locally, and only ever sends read-only calls or already-signed raw transactions. The server sees no keys and logs nothing about these calls. Method- and payload-restricted.",
        "x-rate-limit": 240,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chain",
                  "method"
                ],
                "properties": {
                  "chain": {
                    "type": "string",
                    "description": "EVM chain id"
                  },
                  "method": {
                    "type": "string",
                    "description": "JSON-RPC method (allowlisted)"
                  },
                  "params": {
                    "type": "array",
                    "items": {}
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The upstream JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Method or payload outside the relay's narrow allowance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Shared bucket exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}
