{
  "openapi": "3.1.0",
  "info": {
    "title": "Finotaur Public API",
    "version": "1.0.0",
    "summary": "The public, unauthenticated surface of the Finotaur API.",
    "description": "Finotaur is an AI-powered trading journal and market-intelligence platform for futures, prop-firm and retail traders (https://www.finotaur.com).\n\nThis specification deliberately documents ONLY the public, unauthenticated API surface. Application endpoints (journal, research, analytics, AI features) exist under the same /api base but require a Finotaur account: they are authenticated with a Supabase-issued JWT sent as `Authorization: Bearer <token>` and are scoped per user by row-level security and subscription tier. Finotaur does not currently offer a self-serve developer API-key program or OAuth authorization server with named scopes; rather than fabricate one, this spec describes exactly what is public today. If that changes, this document will grow.\n\nError contract: every error response is structured JSON — never an HTML page — with a machine-readable `error` code, the request `path` where relevant, and a `requestId` for support correlation.\n\nRate limiting: rate-limited endpoints return `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (delta-seconds) response headers, plus legacy `X-RateLimit-*` equivalents. A 429 response additionally carries `Retry-After` (delta-seconds) and a JSON body with `error: \"rate_limit_exceeded\"` and `retryAfter`.\n\nMore machine-readable resources: https://www.finotaur.com/llms.txt (AI-assistant overview), https://www.finotaur.com/pricing.md and https://www.finotaur.com/comparison.md (plain-markdown data), https://www.finotaur.com/developers (human-readable hub).",
    "termsOfService": "https://www.finotaur.com/legal/terms",
    "contact": {
      "name": "Finotaur Support",
      "email": "support@finotaur.com",
      "url": "https://www.finotaur.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://www.finotaur.com/api",
      "description": "Production"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Service health check",
        "description": "Liveness probe for the Finotaur API. Returns `ok: true` and the server timestamp when the API is up. Public, unauthenticated, safe to poll.",
        "tags": ["public"],
        "security": [],
        "responses": {
          "200": {
            "description": "The API is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "ts"],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Always true when the service is healthy.",
                      "const": true
                    },
                    "ts": {
                      "type": "integer",
                      "description": "Server time as a Unix epoch timestamp in milliseconds.",
                      "examples": [1756014740535]
                    }
                  }
                },
                "examples": {
                  "healthy": {
                    "value": { "ok": true, "ts": 1756014740535 }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    },
    "/status": {
      "get": {
        "operationId": "getMarketStatus",
        "summary": "US equity market session status",
        "description": "Current US equity (NYSE/NASDAQ) market session as Finotaur sees it: whether the market is open, which session applies (pre-market, open, after-hours, closed), and a human-readable message. Public, unauthenticated. Useful for agents that need to know whether quoted prices are live or last-close.",
        "tags": ["public"],
        "security": [],
        "responses": {
          "200": {
            "description": "Current market session status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["timestamp", "isOpen", "session", "message"],
                  "properties": {
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "Server time the status was computed, ISO 8601 UTC."
                    },
                    "isOpen": {
                      "type": "boolean",
                      "description": "True only during the regular US equity session (9:30 AM - 4:00 PM ET on trading days)."
                    },
                    "session": {
                      "type": "string",
                      "description": "The current session bucket.",
                      "examples": ["closed", "pre-market", "open", "after-hours"]
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable session summary.",
                      "examples": ["Market closed. Pre-market opens at 4:00 AM ET"]
                    }
                  }
                },
                "examples": {
                  "closed": {
                    "value": {
                      "timestamp": "2026-08-24T05:52:20.535Z",
                      "isOpen": false,
                      "session": "closed",
                      "message": "Market closed. Pre-market opens at 4:00 AM ET"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/ErrorResponse"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Supabase-issued JWT for a Finotaur account, sent as `Authorization: Bearer <token>`. Required by all non-public application endpoints (journal, research, analytics, AI). Access is scoped per user by row-level security and by subscription tier; there are no separately named OAuth scopes today. Tokens are obtained by signing in to Finotaur — there is no self-serve API-key program yet."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Structured error body returned by every Finotaur API error. Never HTML.",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable error code, snake_case.",
            "examples": ["not_found", "rate_limit_exceeded", "unauthorized"]
          },
          "path": {
            "type": "string",
            "description": "The request path that produced the error, when relevant.",
            "examples": ["/api/nonexistent-endpoint"]
          },
          "requestId": {
            "type": "string",
            "description": "Correlation id for support. Quote it when contacting support@finotaur.com.",
            "examples": ["cec55448-6658-4924-b839-b53c75c0e07f"]
          },
          "retryAfter": {
            "type": "integer",
            "description": "Present on 429 responses: seconds to wait before retrying. Mirrors the Retry-After header."
          }
        }
      }
    },
    "responses": {
      "ErrorResponse": {
        "description": "Structured JSON error. 404 for unknown paths, 401 for missing/invalid auth on protected endpoints, 429 when rate-limited (with Retry-After and RateLimit-* headers), 5xx on server faults.",
        "headers": {
          "RateLimit-Limit": {
            "description": "Request quota for the current window (present on rate-limited endpoints).",
            "schema": { "type": "integer" }
          },
          "RateLimit-Remaining": {
            "description": "Requests remaining in the current window.",
            "schema": { "type": "integer" }
          },
          "RateLimit-Reset": {
            "description": "Seconds until the current window resets.",
            "schema": { "type": "integer" }
          },
          "Retry-After": {
            "description": "Seconds to wait before retrying. Sent with 429 responses.",
            "schema": { "type": "integer" }
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "public",
      "description": "Public, unauthenticated endpoints. Everything else under /api requires a Finotaur account (see bearerAuth)."
    }
  ]
}
