{
  "openapi": "3.1.0",
  "info": {
    "title": "price-alert API",
    "version": "2.0.0",
    "description": "Resource-oriented API for OKX instruments, quotes, and price alerts.",
    "license": { "name": "UNLICENSED", "identifier": "UNLICENSED" }
  },
  "servers": [{ "url": "/api/v2" }],
  "security": [{ "bearerAuth": [] }],
  "x-resource-limits": {
    "instruments": 100,
    "alerts": 1000,
    "alertsPerInstrument": 100,
    "batchSize": 100,
    "defaultPageSize": 50,
    "maximumPageSize": 100,
    "requestBodyBytes": 16384,
    "readRequestsPerMinutePerToken": 120,
    "writeRequestsPerMinutePerToken": 30
  },
  "paths": {
    "/alerts": {
      "get": {
        "summary": "List alerts",
        "operationId": "listAlerts",
        "parameters": [
          { "$ref": "#/components/parameters/InstrumentIdQuery" },
          { "name": "direction", "in": "query", "schema": { "$ref": "#/components/schemas/Direction" } },
          { "name": "enabled", "in": "query", "schema": { "type": "boolean" } },
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" }
        ],
        "responses": {
          "200": {
            "description": "Alert page",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertListResponse" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "summary": "Create an alert",
        "operationId": "createAlert",
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateAlert" } } }
        },
        "responses": {
          "201": {
            "description": "Alert created",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponse" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "409": { "$ref": "#/components/responses/LimitReached" },
          "413": { "$ref": "#/components/responses/BodyTooLarge" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/alerts/{alert_id}": {
      "parameters": [{ "$ref": "#/components/parameters/AlertId" }],
      "get": {
        "summary": "Get an alert",
        "operationId": "getAlert",
        "responses": {
          "200": { "description": "Alert", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "summary": "Update an alert",
        "operationId": "updateAlert",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateAlert" } } } },
        "responses": {
          "200": { "description": "Alert updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AlertResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "413": { "$ref": "#/components/responses/BodyTooLarge" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "summary": "Delete an alert",
        "operationId": "deleteAlert",
        "responses": {
          "200": { "description": "Alert deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteAlertResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/alerts/actions/pause": { "$ref": "#/components/pathItems/BatchPause" },
    "/alerts/actions/resume": { "$ref": "#/components/pathItems/BatchResume" },
    "/alerts/actions/delete": { "$ref": "#/components/pathItems/BatchDelete" },
    "/instruments": {
      "get": {
        "summary": "List monitored instruments",
        "operationId": "listInstruments",
        "parameters": [{ "$ref": "#/components/parameters/Limit" }, { "$ref": "#/components/parameters/Cursor" }],
        "responses": {
          "200": { "description": "Instrument page", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstrumentListResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/instruments/{instrument_id}": {
      "get": {
        "summary": "Get a monitored instrument",
        "operationId": "getInstrument",
        "parameters": [{ "$ref": "#/components/parameters/InstrumentId" }],
        "responses": {
          "200": { "description": "Instrument", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstrumentResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/quotes": {
      "get": {
        "summary": "Get quotes for selected instruments",
        "operationId": "listQuotes",
        "parameters": [{ "name": "instrument_id", "in": "query", "required": true, "schema": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/InstrumentId" } }, "style": "form", "explode": true }],
        "responses": {
          "200": { "description": "Requested quotes", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuoteListResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/quotes/{instrument_id}": {
      "get": {
        "summary": "Get the latest instrument quote",
        "operationId": "getQuote",
        "parameters": [{ "$ref": "#/components/parameters/InstrumentId" }],
        "responses": {
          "200": { "description": "Latest quote", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QuoteResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/status": {
      "get": {
        "summary": "Get operational status",
        "operationId": "getStatus",
        "responses": {
          "200": { "description": "Operational status and effective limits", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StatusResponse" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer" }
    },
    "parameters": {
      "AlertId": { "name": "alert_id", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/ResourceId" } },
      "InstrumentId": { "name": "instrument_id", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/InstrumentId" } },
      "InstrumentIdQuery": { "name": "instrument_id", "in": "query", "schema": { "$ref": "#/components/schemas/InstrumentId" } },
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 128 } },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
      "Cursor": { "name": "cursor", "in": "query", "schema": { "type": "string", "minLength": 1, "maxLength": 512 } }
    },
    "pathItems": {
      "BatchPause": {
        "post": {
          "summary": "Pause selected alerts",
          "operationId": "pauseAlerts",
          "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchAlertAction" } } } },
          "responses": { "200": { "$ref": "#/components/responses/BatchUpdated" }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "413": { "$ref": "#/components/responses/BodyTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" } }
        }
      },
      "BatchResume": {
        "post": {
          "summary": "Resume selected alerts",
          "operationId": "resumeAlerts",
          "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchAlertAction" } } } },
          "responses": { "200": { "$ref": "#/components/responses/BatchUpdated" }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "413": { "$ref": "#/components/responses/BodyTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" } }
        }
      },
      "BatchDelete": {
        "post": {
          "summary": "Delete selected alerts",
          "operationId": "deleteAlerts",
          "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchAlertAction" } } } },
          "responses": { "200": { "$ref": "#/components/responses/BatchDeleted" }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/BodyTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" } }
        }
      }
    },
    "responses": {
      "BadRequest": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "Unauthorized": { "description": "Bearer token missing or invalid", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "NotFound": { "description": "Resource not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "LimitReached": { "description": "INSTRUMENT_LIMIT_REACHED, ALERT_LIMIT_REACHED, or INSTRUMENT_ALERT_LIMIT_REACHED", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "BodyTooLarge": { "description": "BODY_TOO_LARGE", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "RateLimited": { "description": "RATE_LIMITED", "headers": { "Retry-After": { "required": true, "schema": { "type": "integer", "minimum": 1 } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
      "BatchUpdated": { "description": "Alerts updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchActionResponse" } } } },
      "BatchDeleted": { "description": "Alerts deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchDeleteResponse" } } } }
    },
    "schemas": {
      "ResourceId": { "type": "string", "pattern": "^[0-9A-HJKMNP-TV-Z]{26}$" },
      "InstrumentId": { "type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[A-Z0-9-]+$" },
      "Direction": { "type": "string", "enum": ["above", "below"] },
      "Decimal": { "type": "string", "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$" },
      "Timestamp": { "type": "string", "format": "date-time" },
      "CreateAlert": {
        "type": "object",
        "additionalProperties": false,
        "required": ["instrument_id", "direction", "threshold"],
        "properties": {
          "instrument_id": { "$ref": "#/components/schemas/InstrumentId" },
          "direction": { "$ref": "#/components/schemas/Direction" },
          "threshold": { "$ref": "#/components/schemas/Decimal" },
          "reset_gap": { "$ref": "#/components/schemas/Decimal", "default": "100" },
          "label": { "type": "string", "maxLength": 100 }
        }
      },
      "UpdateAlert": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "threshold": { "$ref": "#/components/schemas/Decimal" },
          "reset_gap": { "$ref": "#/components/schemas/Decimal" },
          "label": { "type": "string", "maxLength": 100 },
          "enabled": { "type": "boolean" }
        }
      },
      "Alert": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "instrument_id", "direction", "threshold", "reset_gap", "label", "enabled", "armed", "last_triggered_at", "created_at", "updated_at"],
        "properties": {
          "id": { "$ref": "#/components/schemas/ResourceId" },
          "instrument_id": { "$ref": "#/components/schemas/InstrumentId" },
          "direction": { "$ref": "#/components/schemas/Direction" },
          "threshold": { "$ref": "#/components/schemas/Decimal" },
          "reset_gap": { "$ref": "#/components/schemas/Decimal" },
          "label": { "type": "string", "maxLength": 100 },
          "enabled": { "type": "boolean" },
          "armed": { "type": "boolean" },
          "last_triggered_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] },
          "created_at": { "$ref": "#/components/schemas/Timestamp" },
          "updated_at": { "$ref": "#/components/schemas/Timestamp" }
        }
      },
      "Instrument": { "type": "object", "additionalProperties": false, "required": ["id", "provider", "enabled", "alert_count"], "properties": { "id": { "$ref": "#/components/schemas/InstrumentId" }, "provider": { "const": "okx" }, "enabled": { "type": "boolean" }, "alert_count": { "type": "integer", "minimum": 0, "maximum": 100 } } },
      "Quote": { "type": "object", "additionalProperties": false, "required": ["instrument_id", "price", "source", "source_timestamp", "received_at", "stale"], "properties": { "instrument_id": { "$ref": "#/components/schemas/InstrumentId" }, "price": { "$ref": "#/components/schemas/Decimal" }, "source": { "const": "okx" }, "source_timestamp": { "$ref": "#/components/schemas/Timestamp" }, "received_at": { "$ref": "#/components/schemas/Timestamp" }, "stale": { "type": "boolean" } } },
      "BatchAlertAction": { "type": "object", "additionalProperties": false, "required": ["alert_ids"], "properties": { "alert_ids": { "type": "array", "minItems": 1, "maxItems": 100, "uniqueItems": true, "items": { "$ref": "#/components/schemas/ResourceId" } } } },
      "Limits": { "type": "object", "additionalProperties": false, "required": ["instruments", "alerts", "alerts_per_instrument", "batch_size", "default_page_size", "maximum_page_size", "request_body_bytes", "read_requests_per_minute", "write_requests_per_minute"], "properties": { "instruments": { "type": "integer", "minimum": 0 }, "alerts": { "type": "integer", "minimum": 0 }, "alerts_per_instrument": { "type": "integer", "minimum": 0 }, "batch_size": { "type": "integer", "minimum": 0 }, "default_page_size": { "type": "integer", "minimum": 0 }, "maximum_page_size": { "type": "integer", "minimum": 0 }, "request_body_bytes": { "type": "integer", "minimum": 0 }, "read_requests_per_minute": { "type": "integer", "minimum": 0 }, "write_requests_per_minute": { "type": "integer", "minimum": 0 } } },
      "PersistenceStatus": { "type": "object", "additionalProperties": false, "required": ["status", "last_failure_at"], "properties": { "status": { "enum": ["ok", "degraded"] }, "last_failure_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] } } },
      "MarketStatus": { "type": "object", "additionalProperties": false, "required": ["websocket", "subscriptions", "stale_quotes", "last_message_at", "consecutive_failures", "last_failure_at"], "properties": { "websocket": { "enum": ["connected", "reconnecting"] }, "subscriptions": { "type": "integer", "minimum": 0, "maximum": 100 }, "stale_quotes": { "type": "integer", "minimum": 0 }, "last_message_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] }, "consecutive_failures": { "type": "integer", "minimum": 0 }, "last_failure_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] } } },
      "AlertSummary": { "type": "object", "additionalProperties": false, "required": ["total", "enabled", "paused", "armed", "waiting_to_rearm"], "properties": { "total": { "type": "integer", "minimum": 0, "maximum": 1000 }, "enabled": { "type": "integer", "minimum": 0 }, "paused": { "type": "integer", "minimum": 0 }, "armed": { "type": "integer", "minimum": 0 }, "waiting_to_rearm": { "type": "integer", "minimum": 0 } } },
      "ApiMetrics": { "type": "object", "additionalProperties": false, "description": "Rolling five-minute request metrics", "required": ["window_seconds", "requests", "success_rate", "responses_4xx", "responses_5xx", "rate_limited", "average_response_ms"], "properties": { "window_seconds": { "const": 300 }, "requests": { "type": "integer", "minimum": 0 }, "success_rate": { "type": "number", "minimum": 0, "maximum": 1 }, "responses_4xx": { "type": "integer", "minimum": 0 }, "responses_5xx": { "type": "integer", "minimum": 0 }, "rate_limited": { "type": "integer", "minimum": 0 }, "average_response_ms": { "type": "number", "minimum": 0 } } },
      "BarkStatus": { "type": "object", "additionalProperties": false, "required": ["status", "last_success_at", "last_failure_at", "consecutive_failures", "sent_last_24_hours"], "properties": { "status": { "enum": ["unknown_or_ok", "degraded"] }, "last_success_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] }, "last_failure_at": { "oneOf": [{ "$ref": "#/components/schemas/Timestamp" }, { "type": "null" }] }, "consecutive_failures": { "type": "integer", "minimum": 0 }, "sent_last_24_hours": { "type": "integer", "minimum": 0 } } },
      "Status": { "type": "object", "additionalProperties": false, "required": ["status", "version", "uptime_seconds", "updated_at", "memory_bytes", "persistence", "market", "alerts", "api", "bark", "limits"], "properties": { "status": { "enum": ["ok", "degraded", "failed"] }, "version": { "type": "string" }, "uptime_seconds": { "type": "integer", "minimum": 0 }, "updated_at": { "$ref": "#/components/schemas/Timestamp" }, "memory_bytes": { "type": "integer", "minimum": 0 }, "persistence": { "$ref": "#/components/schemas/PersistenceStatus" }, "market": { "$ref": "#/components/schemas/MarketStatus" }, "alerts": { "$ref": "#/components/schemas/AlertSummary" }, "api": { "$ref": "#/components/schemas/ApiMetrics" }, "bark": { "$ref": "#/components/schemas/BarkStatus" }, "limits": { "$ref": "#/components/schemas/Limits" } } },
      "Error": { "type": "object", "additionalProperties": false, "required": ["code", "message"], "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "details": { "type": "object" } } },
      "AlertResponse": { "$ref": "#/components/schemas/SuccessAlert" },
      "AlertListResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "object", "required": ["items", "next_cursor"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Alert" } }, "next_cursor": { "type": ["string", "null"] } } }, "request_id": { "type": "string" } } },
      "InstrumentResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "$ref": "#/components/schemas/Instrument" }, "request_id": { "type": "string" } } },
      "InstrumentListResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "object", "required": ["items", "next_cursor"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Instrument" } }, "next_cursor": { "type": ["string", "null"] } } }, "request_id": { "type": "string" } } },
      "QuoteResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "$ref": "#/components/schemas/Quote" }, "request_id": { "type": "string" } } },
      "QuoteListResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "array", "items": { "$ref": "#/components/schemas/Quote" } }, "request_id": { "type": "string" } } },
      "StatusResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "$ref": "#/components/schemas/Status" }, "request_id": { "type": "string" } } },
      "BatchActionResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "object", "required": ["updated_ids"], "properties": { "updated_ids": { "type": "array", "items": { "$ref": "#/components/schemas/ResourceId" } } } }, "request_id": { "type": "string" } } },
      "BatchDeleteResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "object", "required": ["deleted_ids"], "properties": { "deleted_ids": { "type": "array", "items": { "$ref": "#/components/schemas/ResourceId" } } } }, "request_id": { "type": "string" } } },
      "DeleteAlertResponse": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "type": "object", "required": ["deleted_id"], "properties": { "deleted_id": { "$ref": "#/components/schemas/ResourceId" } } }, "request_id": { "type": "string" } } },
      "ErrorResponse": { "type": "object", "additionalProperties": false, "required": ["ok", "error", "request_id"], "properties": { "ok": { "const": false }, "error": { "$ref": "#/components/schemas/Error" }, "request_id": { "type": "string" } } },
      "SuccessAlert": { "type": "object", "required": ["ok", "data", "request_id"], "properties": { "ok": { "const": true }, "data": { "$ref": "#/components/schemas/Alert" }, "request_id": { "type": "string" } } }
    }
  }
}
