{
  "openapi": "3.1.0",
  "info": {
    "title": "Sablebolt API",
    "version": "1.0.0",
    "summary": "Account-free crypto swaps between two addresses.",
    "description": "Public API behind sablebolt.io. All amounts are decimal strings. Assets are identified by site slugs such as `btc` or `usdt-trc20`. Every success response is wrapped as `{ \"data\": ... }`; every error as `{ \"error\": { \"code\", \"message\" } }`. Swaps follow a floating rate: the final payout can differ slightly from the estimate. No account or sign-up is involved — a swap needs a destination address and, optionally, a refund address. The same read operations are available to assistants over the Model Context Protocol at `POST /mcp` (Streamable HTTP, stateless, no credentials)."
  },
  "servers": [
    {
      "url": "https://api.sablebolt.io"
    }
  ],
  "tags": [
    {
      "name": "system"
    },
    {
      "name": "catalog",
      "description": "Assets and routes the service can swap today."
    },
    {
      "name": "pricing",
      "description": "Limits and floating-rate quotes."
    },
    {
      "name": "swaps",
      "description": "Create a swap and follow its status."
    },
    {
      "name": "market",
      "description": "Cached public market data (USD)."
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "tags": [
          "system"
        ],
        "summary": "Service health",
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Health"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/assets": {
      "get": {
        "tags": [
          "catalog"
        ],
        "summary": "List every swappable asset with availability",
        "operationId": "listAssets",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Asset"
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        },
        "description": "The core assets (those with pages on the site) and the catalogue: every other asset the service swaps. Slugs are the site's own identifiers; use them in every other call."
      }
    },
    "/v1/routes": {
      "get": {
        "tags": [
          "catalog"
        ],
        "summary": "List published swap routes with availability",
        "operationId": "listRoutes",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Route"
                      }
                    }
                  }
                }
              }
            }
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/limits": {
      "get": {
        "tags": [
          "pricing"
        ],
        "summary": "Minimum and maximum amount for a route",
        "operationId": "getLimits",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Slug"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Slug"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Limits"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/quote": {
      "get": {
        "tags": [
          "pricing"
        ],
        "summary": "Floating-rate quote",
        "operationId": "getQuote",
        "description": "`receiveAmount = amountTo − networkFee`; `rate = receiveAmount / amountFrom`. Quotes are indicative; the swap is settled at the rate current when the deposit is received.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Slug"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Slug"
            }
          },
          {
            "name": "amount",
            "in": "query",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/Decimal"
            },
            "description": "Amount of `from` to send."
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/QuoteOk"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      },
      "post": {
        "tags": [
          "pricing"
        ],
        "summary": "Floating-rate quote (JSON body)",
        "operationId": "postQuote",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/QuoteOk"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/address/validate": {
      "post": {
        "tags": [
          "swaps"
        ],
        "summary": "Check an address format for an asset",
        "operationId": "validateAddress",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressValidateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AddressValidation"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/swaps": {
      "post": {
        "tags": [
          "swaps"
        ],
        "summary": "Create a swap",
        "operationId": "createSwap",
        "description": "Returns the deposit address to send `amountFrom` of `from` to. Payout goes to `toAddress` once the deposit is confirmed and exchanged.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SwapCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/SwapCreated"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/swaps/{id}": {
      "get": {
        "tags": [
          "swaps"
        ],
        "summary": "Swap status",
        "operationId": "getSwap",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/SwapId"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/SwapStatus"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/market/prices": {
      "get": {
        "tags": [
          "market"
        ],
        "summary": "USD prices for market ids",
        "operationId": "getMarketPrices",
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]+(,[a-z0-9-]+){0,39}$"
            },
            "description": "1–40 comma-separated market ids (only ids of assets listed by /v1/assets) (the `coinGeckoId` of an asset)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK (Cache-Control: public, max-age=60)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "type": "object",
                      "additionalProperties": {
                        "$ref": "#/components/schemas/MarketPrice"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/MarketMeta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/market/chart/{id}": {
      "get": {
        "tags": [
          "market"
        ],
        "summary": "USD price history for one market id",
        "operationId": "getMarketChart",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,64}$"
            }
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "7",
                "30",
                "365"
              ],
              "default": "7"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK (Cache-Control: public, max-age=300)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/MarketChart"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/MarketMeta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "502": {
            "$ref": "#/components/responses/Upstream"
          }
        }
      }
    },
    "/v1/network/{chain}": {
      "get": {
        "tags": [
          "market"
        ],
        "summary": "Live network statistics for a chain (currently btc), cached 60 s",
        "parameters": [
          {
            "name": "chain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "btc"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ data: { chain, source, fetchedAt, items: [{ k, v }] } }"
          },
          "400": {
            "description": "unknown chain"
          },
          "502": {
            "description": "upstream unavailable"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Slug": {
        "type": "string",
        "pattern": "^[a-z0-9-]{2,24}$",
        "description": "Asset slug as listed by /v1/assets.",
        "examples": [
          "btc",
          "usdt-trc20"
        ]
      },
      "Decimal": {
        "type": "string",
        "pattern": "^\\d+(\\.\\d+)?$",
        "description": "Non-negative decimal number as a string.",
        "examples": [
          "0.0025",
          "150"
        ]
      },
      "SwapId": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_-]{4,64}$"
      },
      "Address": {
        "type": "string",
        "pattern": "^[A-Za-z0-9_\\-:.]{10,128}$"
      },
      "Health": {
        "type": "object",
        "required": [
          "status",
          "mode",
          "time"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "mode": {
            "type": "string",
            "enum": [
              "mock",
              "live"
            ]
          },
          "time": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Asset": {
        "type": "object",
        "required": [
          "slug",
          "ticker",
          "name",
          "network",
          "tag",
          "chain",
          "family",
          "confirmations",
          "extraIdName",
          "explorerTx",
          "coinGeckoId",
          "available"
        ],
        "properties": {
          "slug": {
            "$ref": "#/components/schemas/Slug"
          },
          "ticker": {
            "type": "string",
            "examples": [
              "USDT"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Tether"
            ]
          },
          "network": {
            "type": [
              "string",
              "null"
            ],
            "description": "Network label for multi-network tokens; null for native coins.",
            "examples": [
              "TRON (TRC-20)"
            ]
          },
          "tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short network label for chips (TRC-20, ERC-20, Solana); null for native coins.",
            "examples": [
              "TRC-20"
            ]
          },
          "chain": {
            "type": [
              "string",
              "null"
            ],
            "description": "Chain key the asset lives on (bitcoin, ethereum, tron, binance_smart_chain, solana, arbitrum…).",
            "examples": [
              "tron"
            ]
          },
          "family": {
            "type": "string",
            "description": "Coin family: the same for every network of one token (usdt-trc20 and usdt-solana are both `tether`).",
            "examples": [
              "tether"
            ]
          },
          "confirmations": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Deposit confirmations required before the exchange starts."
          },
          "extraIdName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name of the extra field the chain uses (e.g. Destination Tag, Memo), or null."
          },
          "explorerTx": {
            "type": [
              "string",
              "null"
            ],
            "description": "Explorer URL template; `%1$s` is the transaction hash."
          },
          "coinGeckoId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Market id for /v1/market endpoints."
          },
          "available": {
            "type": "boolean",
            "description": "Whether the asset can be swapped right now."
          }
        }
      },
      "Route": {
        "type": "object",
        "required": [
          "from",
          "to",
          "available"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Slug"
          },
          "to": {
            "$ref": "#/components/schemas/Slug"
          },
          "available": {
            "type": "boolean"
          }
        }
      },
      "Limits": {
        "type": "object",
        "required": [
          "from",
          "to",
          "min",
          "max"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Slug"
          },
          "to": {
            "$ref": "#/components/schemas/Slug"
          },
          "min": {
            "$ref": "#/components/schemas/Decimal"
          },
          "max": {
            "$ref": "#/components/schemas/Decimal"
          }
        }
      },
      "QuoteRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "amount"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Slug"
          },
          "to": {
            "$ref": "#/components/schemas/Slug"
          },
          "amount": {
            "$ref": "#/components/schemas/Decimal"
          }
        }
      },
      "Quote": {
        "type": "object",
        "required": [
          "from",
          "to",
          "amountFrom",
          "amountTo",
          "networkFee",
          "receiveAmount",
          "rate",
          "fetchedAt"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Slug"
          },
          "to": {
            "$ref": "#/components/schemas/Slug"
          },
          "amountFrom": {
            "$ref": "#/components/schemas/Decimal"
          },
          "amountTo": {
            "$ref": "#/components/schemas/Decimal",
            "description": "Estimated amount of `to` before the payout network fee."
          },
          "networkFee": {
            "$ref": "#/components/schemas/Decimal",
            "description": "Payout network fee in units of `to`."
          },
          "receiveAmount": {
            "$ref": "#/components/schemas/Decimal",
            "description": "amountTo − networkFee."
          },
          "rate": {
            "$ref": "#/components/schemas/Decimal",
            "description": "receiveAmount / amountFrom."
          },
          "fetchedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AddressValidateRequest": {
        "type": "object",
        "required": [
          "asset",
          "address"
        ],
        "properties": {
          "asset": {
            "$ref": "#/components/schemas/Slug"
          },
          "address": {
            "type": "string",
            "maxLength": 128
          }
        }
      },
      "AddressValidation": {
        "type": "object",
        "required": [
          "valid"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "message": {
            "type": "string",
            "description": "Present when `valid` is false."
          }
        }
      },
      "SwapCreateRequest": {
        "type": "object",
        "required": [
          "from",
          "to",
          "amount",
          "fromAddress",
          "toAddress"
        ],
        "properties": {
          "from": {
            "$ref": "#/components/schemas/Slug"
          },
          "to": {
            "$ref": "#/components/schemas/Slug"
          },
          "amount": {
            "$ref": "#/components/schemas/Decimal",
            "description": "Amount of `from` you will send."
          },
          "fromAddress": {
            "$ref": "#/components/schemas/Address",
            "description": "The wallet address you will send the deposit from, on the `from` network. Checked like `toAddress` and passed to the liquidity partner, which screens it when the swap is created. There is no refund address: a swap that cannot be completed is handled by support."
          },
          "fromExtraId": {
            "type": "string",
            "maxLength": 200,
            "description": "Tag / memo of the sending address, only when the `from` asset has an `extraIdName`."
          },
          "toAddress": {
            "$ref": "#/components/schemas/Address",
            "description": "Destination address on the `to` network."
          },
          "extraId": {
            "type": "string",
            "maxLength": 200,
            "description": "Destination tag / memo for `to`, only when the asset has an `extraIdName`."
          }
        }
      },
      "SwapCreated": {
        "type": "object",
        "required": [
          "id",
          "depositAddress",
          "depositExtraId",
          "payoutAddress",
          "amountFrom",
          "expectedTo",
          "networkFee",
          "receiveAmount",
          "createdAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/SwapId"
          },
          "depositAddress": {
            "type": "string",
            "description": "Send exactly `amountFrom` of `from` here."
          },
          "depositExtraId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tag/memo to include with the deposit when the `from` chain needs one."
          },
          "payoutAddress": {
            "type": "string"
          },
          "amountFrom": {
            "$ref": "#/components/schemas/Decimal"
          },
          "expectedTo": {
            "$ref": "#/components/schemas/Decimal",
            "description": "Estimated payout before the network fee."
          },
          "networkFee": {
            "$ref": "#/components/schemas/Decimal"
          },
          "receiveAmount": {
            "$ref": "#/components/schemas/Decimal",
            "description": "expectedTo − networkFee."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SwapStatus": {
        "type": "object",
        "required": [
          "id",
          "status",
          "stage",
          "from",
          "to",
          "depositAddress",
          "depositExtraId",
          "payoutAddress",
          "amountFrom",
          "expectedTo",
          "amountTo",
          "networkFee",
          "txIn",
          "txOut",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/SwapId"
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "confirming",
              "exchanging",
              "sending",
              "finished",
              "failed",
              "refunded",
              "expired",
              "hold",
              "unknown"
            ]
          },
          "stage": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "description": "1 waiting, 2 confirming, 3 exchanging, 4 sending, 5 finished. Non-progress statuses keep the last stage reached."
          },
          "from": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Slug"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Slug"
              },
              {
                "type": "null"
              }
            ]
          },
          "depositAddress": {
            "type": [
              "string",
              "null"
            ]
          },
          "depositExtraId": {
            "type": [
              "string",
              "null"
            ]
          },
          "payoutAddress": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountFrom": {
            "$ref": "#/components/schemas/Decimal"
          },
          "expectedTo": {
            "$ref": "#/components/schemas/Decimal"
          },
          "amountTo": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Decimal"
              },
              {
                "type": "null"
              }
            ],
            "description": "Actual payout once known, otherwise null."
          },
          "networkFee": {
            "$ref": "#/components/schemas/Decimal"
          },
          "txIn": {
            "type": [
              "string",
              "null"
            ],
            "description": "Deposit transaction hash once seen."
          },
          "txOut": {
            "type": [
              "string",
              "null"
            ],
            "description": "Payout transaction hash once sent."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MarketPrice": {
        "type": "object",
        "properties": {
          "usd": {
            "type": "number"
          },
          "usd_market_cap": {
            "type": "number"
          },
          "usd_24h_vol": {
            "type": "number"
          },
          "usd_24h_change": {
            "type": "number"
          }
        }
      },
      "MarketChart": {
        "type": "object",
        "required": [
          "id",
          "days",
          "prices"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "days": {
            "type": "integer",
            "enum": [
              1,
              7,
              30,
              365
            ]
          },
          "prices": {
            "type": "array",
            "description": "Up to 200 [unixMillis, usdPrice] points.",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "number"
                },
                {
                  "type": "number"
                }
              ],
              "minItems": 2,
              "maxItems": 2
            }
          }
        }
      },
      "MarketMeta": {
        "type": "object",
        "required": [
          "stale"
        ],
        "properties": {
          "stale": {
            "type": "boolean",
            "description": "True when the upstream failed and a cached value is served."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "pattern": "^[a-z_]+$",
                "examples": [
                  "validation_error",
                  "invalid_address",
                  "invalid_sender_address",
                  "amount_below_min",
                  "amount_above_max",
                  "pair_unavailable",
                  "asset_unavailable",
                  "not_found",
                  "rate_limited",
                  "upstream_error",
                  "market_unavailable"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "QuoteOk": {
        "description": "OK",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Upstream": {
        "description": "Upstream unavailable",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
