{
  "openapi": "3.0.3",
  "info": {
    "title": "CopiloTrade Developer API",
    "version": "1.0.0",
    "description": "Read-only access to your own EA's AI signals (AI-1 decisions, AI-2 reviews, AI-3 position checks, real opens/closes), EA status and trades. Signals can also be pushed to your server by webhook (configured in the dashboard). Docs: https://copilotrade.com/docs-api.html",
    "contact": { "name": "CopiloTrade", "url": "https://copilotrade.com/docs-api.html" }
  },
  "servers": [{ "url": "https://copilotrade.com/api/v1" }],
  "security": [{ "bearerAuth": [] }, { "apiKeyHeader": [] }],
  "tags": [
    { "name": "meta" }, { "name": "accounts" }, { "name": "signals" }, { "name": "trades" }
  ],
  "paths": {
    "/ping": {
      "get": { "tags": ["meta"], "summary": "Connectivity check (no auth)", "security": [],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } } }
    },
    "/me": {
      "get": { "tags": ["meta"], "summary": "User, membership and account list behind this key",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MeResponse" } } } }, "401": { "$ref": "#/components/responses/Err" }, "403": { "$ref": "#/components/responses/Err" } } }
    },
    "/accounts": {
      "get": { "tags": ["accounts"], "summary": "My MT5 accounts and EA online state",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountsResponse" } } } }, "401": { "$ref": "#/components/responses/Err" } } }
    },
    "/accounts/{login}/status": {
      "get": { "tags": ["accounts"], "summary": "Latest EA snapshot of one account",
        "parameters": [{ "name": "login", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "MT5 login" }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StatusResponse" } } } }, "404": { "$ref": "#/components/responses/Err" } } }
    },
    "/signals": {
      "get": { "tags": ["signals"], "summary": "List signals (cursor pagination)",
        "parameters": [
          { "name": "account", "in": "query", "schema": { "type": "integer" }, "description": "MT5 login; omit for all my accounts" },
          { "name": "type", "in": "query", "schema": { "$ref": "#/components/schemas/SignalType" } },
          { "name": "since_id", "in": "query", "schema": { "type": "integer" }, "description": "Cursor: only id > since_id, ascending. Without it: newest first, descending." },
          { "name": "since", "in": "query", "schema": { "type": "string" }, "description": "Only after this time: unix ms / unix s / ISO 8601" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SignalsResponse" } } } }, "400": { "$ref": "#/components/responses/Err" }, "404": { "$ref": "#/components/responses/Err" } } }
    },
    "/signals/latest": {
      "get": { "tags": ["signals"], "summary": "Latest signal of a type per account",
        "parameters": [
          { "name": "account", "in": "query", "schema": { "type": "integer" } },
          { "name": "type", "in": "query", "schema": { "$ref": "#/components/schemas/SignalType", "default": "analysis" } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SignalsResponse" } } } } } }
    },
    "/signals/{id}": {
      "get": { "tags": ["signals"], "summary": "One signal",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "properties": { "signal": { "$ref": "#/components/schemas/Signal" } } } } } } } }, "404": { "$ref": "#/components/responses/Err" } } }
    },
    "/trades": {
      "get": { "tags": ["trades"], "summary": "Real trades made by the EA",
        "parameters": [
          { "name": "account", "in": "query", "schema": { "type": "integer" } },
          { "name": "since", "in": "query", "schema": { "type": "string" } },
          { "name": "open", "in": "query", "schema": { "type": "string", "enum": ["0", "1"] }, "description": "1 = open positions only" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TradesResponse" } } } } } }
    },
    "/events": {
      "get": { "tags": ["meta"], "summary": "Signal type list",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } } }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Authorization: Bearer cpt_live_..." },
      "apiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-Key" }
    },
    "responses": {
      "Err": { "description": "Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    },
    "schemas": {
      "Envelope": { "type": "object", "properties": { "ok": { "type": "boolean" }, "server_time": { "type": "integer", "description": "unix ms" }, "data": { "type": "object" } } },
      "Error": { "type": "object", "properties": { "ok": { "type": "boolean", "enum": [false] }, "error": { "type": "object", "properties": { "code": { "type": "string", "enum": ["missing_key", "invalid_key", "membership_expired", "account_disabled", "bad_account", "bad_type", "bad_since_id", "account_not_found", "not_found", "rate_limited", "rate_limited_ip"] }, "message": { "type": "string" }, "message_zh": { "type": "string" } } } } },
      "SignalType": { "type": "string", "enum": ["analysis", "review", "monitor", "trade_open", "trade_close", "trade_result"] },
      "Quote": { "type": "object", "nullable": true, "properties": { "bid": { "type": "number" }, "ask": { "type": "number" }, "spread_points": { "type": "number" }, "point": { "type": "number" }, "digits": { "type": "integer" } } },
      "Levels": { "type": "object", "nullable": true, "description": "Estimated prices from the quote at upload time (ask for buy, bid for sell)", "properties": { "entry": { "type": "number" }, "sl": { "type": "number", "nullable": true }, "tp": { "type": "number", "nullable": true } } },
      "AnalysisData": { "type": "object", "properties": {
        "decision": { "type": "string", "enum": ["buy", "sell", "hold"] }, "confidence": { "type": "integer" }, "market_state": { "type": "string", "nullable": true },
        "sl_points": { "type": "number", "nullable": true }, "tp_points": { "type": "number", "nullable": true }, "levels": { "$ref": "#/components/schemas/Levels" },
        "reason": { "type": "string", "nullable": true }, "duration_sec": { "type": "number", "nullable": true }, "quote": { "$ref": "#/components/schemas/Quote" },
        "atr_points": { "type": "number", "nullable": true }, "atr_timeframe": { "type": "string", "nullable": true }, "model": { "type": "string", "nullable": true } } },
      "ReviewData": { "type": "object", "properties": { "verdict": { "type": "string", "enum": ["approve", "reject"] }, "risk_level": { "type": "string", "nullable": true }, "reason": { "type": "string", "nullable": true }, "duration_sec": { "type": "number", "nullable": true }, "model": { "type": "string", "nullable": true } } },
      "MonitorData": { "type": "object", "properties": { "decision": { "type": "string" }, "confidence": { "type": "integer", "nullable": true }, "new_sl_points": { "type": "number", "nullable": true }, "new_sl_price": { "type": "number", "nullable": true }, "reason": { "type": "string", "nullable": true }, "duration_sec": { "type": "number", "nullable": true }, "position": { "type": "object", "nullable": true }, "quote": { "$ref": "#/components/schemas/Quote" }, "model": { "type": "string", "nullable": true } } },
      "TradeOpenData": { "type": "object", "properties": { "ticket": { "type": "integer" }, "direction": { "type": "string", "enum": ["buy", "sell"] }, "lots": { "type": "number" }, "price": { "type": "number" }, "sl": { "type": "number", "nullable": true }, "tp": { "type": "number", "nullable": true }, "quote_price": { "type": "number", "nullable": true }, "slippage_points": { "type": "number", "nullable": true }, "reanchored": { "type": "boolean" }, "actual_rr": { "type": "number", "nullable": true }, "ai1_confidence": { "type": "integer", "nullable": true }, "ai2_verdict": { "type": "string", "nullable": true }, "magic": { "type": "integer", "nullable": true } } },
      "TradeCloseData": { "type": "object", "properties": { "ticket": { "type": "integer" }, "close_reason": { "type": "string", "nullable": true }, "close_price": { "type": "number", "nullable": true }, "profit": { "type": "number", "nullable": true } } },
      "Signal": { "type": "object", "properties": {
        "id": { "type": "integer" }, "type": { "$ref": "#/components/schemas/SignalType" }, "account": { "type": "integer" }, "symbol": { "type": "string", "nullable": true },
        "parent_id": { "type": "integer", "nullable": true, "description": "The analysis that triggered this review / trade_open" },
        "ea_time": { "type": "string", "nullable": true }, "created_at": { "type": "integer", "description": "unix ms" }, "time": { "type": "string", "format": "date-time" },
        "data": { "oneOf": [ { "$ref": "#/components/schemas/AnalysisData" }, { "$ref": "#/components/schemas/ReviewData" }, { "$ref": "#/components/schemas/MonitorData" }, { "$ref": "#/components/schemas/TradeOpenData" }, { "$ref": "#/components/schemas/TradeCloseData" } ] } } },
      "SignalsResponse": { "type": "object", "properties": { "ok": { "type": "boolean" }, "server_time": { "type": "integer" }, "data": { "type": "object", "properties": { "signals": { "type": "array", "items": { "$ref": "#/components/schemas/Signal" } }, "count": { "type": "integer" }, "next_since_id": { "type": "integer" }, "has_more": { "type": "boolean" } } } } },
      "Trade": { "type": "object", "properties": { "account": { "type": "integer" }, "ticket": { "type": "integer" }, "symbol": { "type": "string" }, "direction": { "type": "string" }, "lots": { "type": "number" }, "open_price": { "type": "number", "nullable": true }, "sl": { "type": "number", "nullable": true }, "tp": { "type": "number", "nullable": true }, "quote_price": { "type": "number", "nullable": true }, "slippage_points": { "type": "number", "nullable": true }, "actual_rr": { "type": "number", "nullable": true }, "ai1_confidence": { "type": "integer", "nullable": true }, "ai2_verdict": { "type": "string", "nullable": true }, "magic": { "type": "integer", "nullable": true }, "open_at": { "type": "integer", "nullable": true }, "open_time": { "type": "string", "nullable": true }, "close_at": { "type": "integer", "nullable": true }, "close_time": { "type": "string", "nullable": true }, "close_price": { "type": "number", "nullable": true }, "profit": { "type": "number", "nullable": true }, "close_reason": { "type": "string", "nullable": true }, "is_open": { "type": "boolean" } } },
      "TradesResponse": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "properties": { "trades": { "type": "array", "items": { "$ref": "#/components/schemas/Trade" } }, "count": { "type": "integer" } } } } },
      "MeResponse": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "properties": { "user_id": { "type": "integer" }, "username": { "type": "string" }, "membership": { "type": "object", "properties": { "expire_date": { "type": "string", "nullable": true }, "days_left": { "type": "integer" } } }, "key": { "type": "object" }, "rate_limit_per_min": { "type": "integer" }, "accounts": { "type": "array", "items": { "type": "integer" } } } } } },
      "AccountsResponse": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "properties": { "accounts": { "type": "array", "items": { "type": "object", "properties": { "account": { "type": "integer" }, "server": { "type": "string" }, "remark": { "type": "string" }, "active": { "type": "boolean" }, "ea_online": { "type": "boolean" }, "ea_last_seen": { "type": "integer", "nullable": true }, "ea_version": { "type": "string", "nullable": true }, "symbol": { "type": "string", "nullable": true }, "ea_state": { "type": "string", "nullable": true }, "has_position": { "type": "boolean" }, "last_signal_at": { "type": "integer", "nullable": true } } } } } } } },
      "StatusResponse": { "type": "object", "properties": { "ok": { "type": "boolean" }, "data": { "type": "object", "description": "See docs: ea_online, status_at, account, symbol, ai1, ai2, ai3, position, today, filters, license, ai_error" } } }
    }
  },
  "x-webhook": {
    "description": "Configured per key in the dashboard. POST JSON { delivery_id, type, key_id, sent_at, signal, test? } with headers X-CopiloTrade-Event, X-CopiloTrade-Delivery, X-CopiloTrade-Timestamp, X-CopiloTrade-Signature: t=<unix s>,v1=<hex HMAC-SHA256(secret, t + '.' + raw_body)>. Respond 2xx within 8 s. Retries at 30 s / 2 min / 10 min / 30 min; auto-disabled after 100 consecutive failures."
  }
}
