{
  "openapi": "3.1.0",
  "info": {
    "title": "fxconverter.tech Exchange Rates API",
    "description": "Live mid-market exchange rates, integer-exact conversions, and 5-year daily history for any currency pair. Rates refresh every 10 minutes; amounts and rates are returned as decimal strings (no float drift). Forward-looking data is deliberately absent — use historical volatility from the history stats, never predictions.",
    "version": "1.0.0",
    "contact": { "email": "api@fxconverter.tech", "url": "https://fxconverter.tech/developers" }
  },
  "servers": [{ "url": "https://fxconverter.tech" }],
  "security": [{ "apiKeyHeader": [] }, { "apiKeyQuery": [] }],
  "paths": {
    "/api/v1/rate": {
      "get": {
        "operationId": "getRate",
        "summary": "Live mid-market rate for one currency pair",
        "parameters": [
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "example": "USD" }, "description": "ISO 4217 source currency" },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "example": "EUR" }, "description": "ISO 4217 target currency" }
        ],
        "responses": {
          "200": {
            "description": "Current rate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pair": { "type": "string", "example": "USDEUR" },
                    "from": { "type": "string", "example": "USD" },
                    "to": { "type": "string", "example": "EUR" },
                    "rate": { "type": "string", "example": "0.8756", "description": "Decimal string" },
                    "asOf": { "type": "string", "format": "date-time" },
                    "stale": { "type": "boolean", "description": "true when serving the last stored rate because the live feed is unavailable" }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid currency pair" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Daily quota exceeded" }
        }
      }
    },
    "/api/v1/convert": {
      "get": {
        "operationId": "convertAmount",
        "summary": "Convert an amount with integer-exact arithmetic",
        "parameters": [
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "example": "USD" } },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "example": "EUR" } },
          { "name": "amount", "in": "query", "required": true, "schema": { "type": "string", "example": "1234.56" }, "description": "Non-negative decimal amount in the source currency" }
        ],
        "responses": {
          "200": {
            "description": "Converted amount",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "from": { "type": "string" },
                    "to": { "type": "string" },
                    "amount": { "type": "string", "example": "1234.56" },
                    "rate": { "type": "string", "example": "0.8756" },
                    "result": { "type": "string", "example": "1080.98" },
                    "asOf": { "type": "string", "format": "date-time" },
                    "stale": { "type": "boolean" }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid pair or amount" },
          "401": { "description": "Missing or invalid API key" },
          "429": { "description": "Daily quota exceeded" }
        }
      }
    },
    "/api/v1/history": {
      "get": {
        "operationId": "getHistory",
        "summary": "Daily rate history with stats (JSON or CSV)",
        "parameters": [
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "example": "USD" } },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "example": "EUR" } },
          { "name": "range", "in": "query", "schema": { "type": "string", "enum": ["1m", "3m", "6m", "1y", "5y"], "default": "1y" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json", "csv"], "default": "json" } }
        ],
        "responses": {
          "200": {
            "description": "Daily closes, ascending, with best/worst/average stats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pair": { "type": "string" },
                    "range": { "type": "string" },
                    "count": { "type": "integer" },
                    "points": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": { "type": "string", "format": "date" },
                          "rate": { "type": "string" }
                        }
                      }
                    },
                    "stats": {
                      "type": "object",
                      "properties": {
                        "best": { "type": "string" },
                        "bestDate": { "type": "string", "format": "date" },
                        "worst": { "type": "string" },
                        "worstDate": { "type": "string", "format": "date" },
                        "average": { "type": "string" },
                        "changePct": { "type": "number" },
                        "currentVsAveragePct": { "type": "number" }
                      }
                    }
                  }
                }
              },
              "text/csv": { "schema": { "type": "string" } }
            }
          },
          "400": { "description": "Invalid pair or range" },
          "401": { "description": "Missing or invalid API key" },
          "404": { "description": "No history available for this pair" },
          "429": { "description": "Daily quota exceeded" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-Api-Key" },
      "apiKeyQuery": { "type": "apiKey", "in": "query", "name": "apikey" }
    }
  }
}
