{
  "openapi": "3.1.1",
  "info": {
    "title": "RavingDesk Crypto Spot Round-Trip Cost Planner API",
    "version": "1.0.0",
    "summary": "What a crypto spot buy-and-sell really costs: spread, slippage, fees, withdrawal and break-even.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://ravingdeskcryptoroundtrip.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "What a crypto spot buy-and-sell really costs: spread, slippage, fees, withdrawal and break-even.",
        "description": "Estimates a hypothetical spot round trip from the mid prices and cost assumptions you enter: buy fill (ask plus slippage), sell fill (bid minus slippage), trading fees on both sides and a network/withdrawal fee in base units, with net profit or loss, return on cost and the exit mid price needed to break even. Nothing is fetched and no order is sent. It is the crypto spot lab of the RavingDesk workspace.\n\nMethodology:\n- Buy fill = entry mid × (1 + spread ÷ 2) × (1 + slippage); sell fill = exit mid × (1 − spread ÷ 2) × (1 − slippage). Spread and slippage are in basis points (1 bp = 0.01 %).\n- Entry cost = quantity × buy fill × (1 + entry fee %); the network fee is deducted in base units, then the remainder is sold: net proceeds = remaining quantity × sell fill × (1 − exit fee %).\n- Break-even exit mid = entry cost ÷ (remaining quantity × (1 − spread ÷ 2) × (1 − slippage) × (1 − exit fee %)). The cost of the round trip is the loss if the mid price does not move.\n- Assumes a full fill at one price per side, fees charged in the quote asset, no market impact beyond the slippage you enter, no taxes and no fees in a third asset.\n\nPaper-trading calculation for education and planning only. It is not investment, tax or legal advice, uses only the numbers you enter and never places an order. Crypto prices and fees change quickly; use the rates of your own venue.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "ravingdesk_crypto_round_trip",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RavingdeskCryptoRoundTripInput"
              },
              "examples": {
                "example1": {
                  "summary": "Fictional BTC round trip: 1 BTC, 60,000 → 62,000, 10 bps spread, 0.1 % fees",
                  "value": {
                    "base": "BTC",
                    "quote": "USDT",
                    "quantity": 1,
                    "entryMid": 60000,
                    "exitMid": 62000,
                    "spreadBps": 10,
                    "slippageBps": 5,
                    "entryFeePercent": 0.1,
                    "exitFeePercent": 0.1,
                    "networkBase": 0
                  }
                },
                "example2": {
                  "summary": "Small ETH trade with a withdrawal fee in between",
                  "value": {
                    "base": "ETH",
                    "quote": "EUR",
                    "quantity": 0.5,
                    "entryMid": 3000,
                    "exitMid": 3050,
                    "spreadBps": 20,
                    "slippageBps": 10,
                    "entryFeePercent": 0.26,
                    "exitFeePercent": 0.26,
                    "networkBase": 0.002
                  }
                },
                "example3": {
                  "summary": "Flat price: what the round trip costs if nothing moves",
                  "value": {
                    "base": "SOL",
                    "quote": "USD",
                    "quantity": 20,
                    "entryMid": 150,
                    "exitMid": 150,
                    "spreadBps": 30,
                    "slippageBps": 15,
                    "entryFeePercent": 0.4,
                    "exitFeePercent": 0.4,
                    "networkBase": 0.01
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RavingdeskCryptoRoundTripResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "RavingdeskCryptoRoundTripInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "base": {
            "title": "Base asset",
            "type": "string",
            "maxLength": 12,
            "default": "BTC"
          },
          "quote": {
            "title": "Quote asset",
            "type": "string",
            "maxLength": 12,
            "default": "USDT"
          },
          "quantity": {
            "title": "Base quantity bought",
            "type": "number",
            "minimum": 1e-8,
            "maximum": 1000000000000,
            "default": 1
          },
          "entryMid": {
            "title": "Entry mid price",
            "type": "number",
            "minimum": 1e-8,
            "maximum": 1000000000000,
            "default": 60000
          },
          "exitMid": {
            "title": "Exit mid price",
            "type": "number",
            "minimum": 1e-8,
            "maximum": 1000000000000,
            "default": 62000
          },
          "spreadBps": {
            "title": "Full bid–ask spread",
            "type": "number",
            "minimum": 0,
            "maximum": 9999,
            "default": 10,
            "x-unit": "bps"
          },
          "slippageBps": {
            "title": "Slippage per side",
            "type": "number",
            "minimum": 0,
            "maximum": 9999,
            "default": 5,
            "x-unit": "bps"
          },
          "entryFeePercent": {
            "title": "Entry trading fee",
            "type": "number",
            "minimum": 0,
            "maximum": 99.99,
            "default": 0.1,
            "x-unit": "%"
          },
          "exitFeePercent": {
            "title": "Exit trading fee",
            "type": "number",
            "minimum": 0,
            "maximum": 99.99,
            "default": 0.1,
            "x-unit": "%"
          },
          "networkBase": {
            "title": "Network / withdrawal fee",
            "description": "In base units, deducted once between buying and selling (e.g. moving coins to another exchange).",
            "type": "number",
            "minimum": 0,
            "maximum": 1000000000000,
            "default": 0
          }
        },
        "required": [
          "quantity",
          "entryMid",
          "exitMid"
        ]
      },
      "RavingdeskCryptoRoundTripResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "buyPrice",
              "sellPrice",
              "acquired",
              "entryFee",
              "exitFee",
              "totalCost",
              "netProceeds",
              "breakEvenMid",
              "breakEvenMovePercent",
              "pnl",
              "returnPercent",
              "costOfRoundTrip"
            ],
            "properties": {
              "buyPrice": {
                "type": "number"
              },
              "sellPrice": {
                "type": "number"
              },
              "acquired": {
                "type": "number"
              },
              "entryNotional": {
                "type": "number"
              },
              "entryFee": {
                "type": "number"
              },
              "exitNotional": {
                "type": "number"
              },
              "exitFee": {
                "type": "number"
              },
              "totalCost": {
                "type": "number"
              },
              "netProceeds": {
                "type": "number"
              },
              "breakEvenMid": {
                "type": "number"
              },
              "breakEvenMovePercent": {
                "type": "number"
              },
              "pnl": {
                "type": "number"
              },
              "returnPercent": {
                "type": "number"
              },
              "costOfRoundTrip": {
                "type": "number"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}