{"openapi": "3.1.0", "info": {"title": "Obsidian Eye", "version": "1.0.0", "summary": "An honest second pair of eyes on any chart.", "description": "Obsidian Eye is the Obsidian trading desk's connector. The calling agent reads the user's screenshot with its own vision; Obsidian Eye supplies the desk framework that governs how the screenshot is read, meters the daily allowance, and saves every read to the user's permanent library. Obsidian Eye performs no inference, holds no brokerage connection, places no orders, and distributes no market data.", "contact": {"url": "https://www.accessobsidian.com/obsidianeyeai"}}, "servers": [{"url": "https://www.accessobsidian.com"}], "components": {"securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer", "description": "An Obsidian Eye API token beginning oe_live_. The user creates a free account with an email address at https://www.accessobsidian.com/obsidianeyeai, issues a token at https://www.accessobsidian.com/obsidianeyeai/account, and supplies the token through the secure credential screen. A token does not expire and is sent on every call. Never ask the user for a token in conversation, and never attempt to create or refresh one: token issue is a browser only action, so a call attempting it is rejected."}}, "schemas": {"Read": {"type": "object", "required": ["kind", "bias", "conviction", "summary", "key_levels", "invalidation", "timeframe", "changes_my_mind", "risks"], "properties": {"ticker": {"type": ["string", "null"], "maxLength": 12}, "kind": {"enum": ["chart", "chain", "positions", "heatmap", "other"]}, "bias": {"enum": ["bullish", "bearish", "neutral"]}, "conviction": {"enum": ["low", "medium", "high"]}, "summary": {"type": "string", "description": "Two to four sentences in the desk voice."}, "key_levels": {"type": "object", "properties": {"support": {"type": "array", "items": {"type": ["string", "number"]}}, "resistance": {"type": "array", "items": {"type": ["string", "number"]}}}}, "invalidation": {"type": "string", "description": "The price or condition that kills the call."}, "timeframe": {"enum": ["intraday", "swing", "positional", "unclear"]}, "changes_my_mind": {"type": "string"}, "risks": {"type": "array", "items": {"type": "string"}}}}}}, "security": [{"bearerAuth": []}], "x-connection-flow": ["The user creates a free account at https://www.accessobsidian.com/obsidianeyeai using an email address. No password and no confirmation email are involved, so the account opens immediately.", "The user issues a connector token at https://www.accessobsidian.com/obsidianeyeai/account and supplies it through the secure credential screen. Ask for the token there rather than in the conversation.", "Send the token as 'Authorization: Bearer oe_live_...' on every call. The token does not expire, so the connection persists."], "x-usage-flow": ["POST /api/v1/session before every read. The call spends nothing and returns the framework plus the reads remaining today. A 402 means the allowance is spent: show the upgrade link and stop.", "Read the user's screenshot yourself, applying the framework text returned by the session call verbatim.", "POST /api/v1/reads with the structured result to save the read. The save is the metered call, so it spends one of the daily allowance and a read that is never saved costs the user nothing.", "Present the read conversationally, ending with: Not financial advice."], "paths": {"/api/v1/session": {"post": {"operationId": "startRead", "summary": "Fetch the desk framework and the reads remaining", "description": "Call before reading a screenshot. Returns the active desk framework, the JSON schema the result must match, and the reads remaining today. Spends no allowance: saving the read is what spends one.", "responses": {"200": {"description": "Allowed. Framework returned."}, "402": {"description": "Daily limit reached. Body carries upgrade_url."}, "429": {"description": "Too many reads requested in one hour."}}}}, "/api/v1/reads": {"post": {"operationId": "saveRead", "summary": "Save a completed read to the user's library", "description": "The metered call. Saving spends one of the user's daily reads and returns the count remaining. A result rejected as invalid spends nothing.", "responses": {"201": {"description": "Saved. Body carries remaining."}, "402": {"description": "Daily limit reached. Nothing was saved."}, "422": {"description": "Result failed validation. Body lists every error."}}}, "get": {"operationId": "listReads", "summary": "List saved reads, newest first", "responses": {"200": {"description": "The user's library."}}}}, "/api/v1/reads/{id}": {"get": {"operationId": "getRead", "summary": "Fetch one saved read", "responses": {"200": {"description": "The read."}}}, "patch": {"operationId": "updateRead", "summary": "Star or tag a read", "responses": {"200": {"description": "Updated."}}}, "delete": {"operationId": "deleteRead", "summary": "Delete a read", "responses": {"200": {"description": "Deleted."}}}}, "/api/v1/me": {"get": {"operationId": "getAccount", "summary": "Plan, reads used today, and the daily limit", "responses": {"200": {"description": "Account status."}}}}}}