{
  "openapi": "3.1.0",
  "info": {
    "title": "pool-api",
    "description": "",
    "license": {
      "name": "MIT OR Apache-2.0",
      "identifier": "MIT OR Apache-2.0"
    },
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://api.icemining.ca/api/v1",
      "description": "Production active API endpoint."
    },
    {
      "url": "https://api-devnet.icemining.ca/api/v1",
      "description": "Devnet active API endpoint."
    }
  ],
  "paths": {
    "/coin/{coin_id}": {
      "get": {
        "tags": [
          "Public"
        ],
        "operationId": "public_coin",
        "parameters": [
          {
            "name": "coin_id",
            "in": "path",
            "description": "Coin slug, symbol, reward unit, or numeric coin id. Example: prl.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current public snapshot filtered by coin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCoinSnapshotV1"
                }
              }
            }
          },
          "404": {
            "description": "Coin not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Public snapshot unavailable or stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        }
      }
    },
    "/coin/{coin_id}/blocks": {
      "get": {
        "tags": [
          "Public"
        ],
        "operationId": "public_coin_blocks_docs",
        "parameters": [
          {
            "name": "coin_id",
            "in": "path",
            "description": "Coin identifier, for example pearl.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Public block data for a coin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPoolSnapshotV1"
                }
              }
            }
          },
          "503": {
            "description": "Public snapshot unavailable or stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        }
      }
    },
    "/coins": {
      "get": {
        "tags": [
          "Public"
        ],
        "operationId": "public_coins",
        "responses": {
          "200": {
            "description": "Current public coin and pool snapshot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPoolSnapshotV1"
                }
              }
            }
          },
          "503": {
            "description": "Public snapshot unavailable or stale.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        }
      }
    },
    "/user": {
      "get": {
        "tags": [
          "User"
        ],
        "operationId": "user_summary",
        "responses": {
          "200": {
            "description": "Authenticated account summary, derived from a single Workers read (`spec/POOL_API_ACCOUNT_DATA.md` §2.5 / §4 decision 2). Body is the same `WorkerHealthSnapshot` projection served by `/api/v1/user/workers`; clients aggregate the latest bucket for the summary counts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerHealthSnapshot"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — per-IP or per-key budget exceeded (`spec/POOL_API_RATE_LIMIT_ABUSE.md` §4). Includes a `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Resolver or account-data read unavailable; retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKeyAuth": []
          }
        ]
      }
    },
    "/user/hashrate": {
      "get": {
        "tags": [
          "User"
        ],
        "operationId": "user_hashrate",
        "responses": {
          "200": {
            "description": "Authenticated hashrate-history projection for the default last-hour range at 30-second resolution. Body is an ICHRHST1 binary chunk (application/octet-stream), not JSON.",
            "content": {
              "application/octet-stream": {}
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — per-IP or per-key budget exceeded (`spec/POOL_API_RATE_LIMIT_ABUSE.md` §4). Includes a `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Resolver or account-data read unavailable; retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKeyAuth": []
          }
        ]
      }
    },
    "/user/payments": {
      "get": {
        "tags": [
          "User"
        ],
        "operationId": "user_payments",
        "responses": {
          "200": {
            "description": "Per-account balances + recent-payouts projection. Same `AccountPayoutsSnapshot` body as `/api/v1/user/payouts`; the kind discriminant differs so a future split needs no wire change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPayoutsSnapshot"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — per-IP or per-key budget exceeded (`spec/POOL_API_RATE_LIMIT_ABUSE.md` §4). Includes a `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Resolver or account-data read unavailable; retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKeyAuth": []
          }
        ]
      }
    },
    "/user/payouts": {
      "get": {
        "tags": [
          "User"
        ],
        "operationId": "user_payouts",
        "responses": {
          "200": {
            "description": "Per-account balances + recent-payouts projection (`spec/POOL_API_ACCOUNT_DATA.md` §2.4).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountPayoutsSnapshot"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — per-IP or per-key budget exceeded (`spec/POOL_API_RATE_LIMIT_ABUSE.md` §4). Includes a `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Resolver or account-data read unavailable; retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKeyAuth": []
          }
        ]
      }
    },
    "/user/workers": {
      "get": {
        "tags": [
          "User"
        ],
        "operationId": "user_workers",
        "responses": {
          "200": {
            "description": "Per-account worker-health projection: a rolling ring of one-minute health buckets (`spec/POOL_API_ACCOUNT_DATA.md` §2.4 status mapping).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkerHealthSnapshot"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited — per-IP or per-key budget exceeded (`spec/POOL_API_RATE_LIMIT_ABUSE.md` §4). Includes a `Retry-After` header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          },
          "503": {
            "description": "Resolver or account-data read unavailable; retry later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiProblem"
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKeyAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AccountPayoutsSnapshot": {
        "type": "object",
        "description": "Doc-only OpenAPI schema mirror of\n`stratum_backend::account_payouts_publisher::AccountPayoutsSnapshot`.\n\nSee [`WorkerHealthSnapshot`] for the mirror rationale. The source struct\nuses `#[serde(rename_all = \"camelCase\")]`; this mirror preserves it.",
        "required": [
          "v",
          "producedUnixMs",
          "balances",
          "recentPayouts"
        ],
        "properties": {
          "balances": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CoinBalance"
            }
          },
          "producedUnixMs": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "recentPayouts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutRow"
            }
          },
          "v": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      },
      "ApiProblem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        }
      },
      "CoinBalance": {
        "type": "object",
        "description": "Doc-only OpenAPI schema mirror of\n`stratum_backend::account_payouts_publisher::CoinBalance`.\n\nSee [`WorkerHealthSnapshot`] for the mirror rationale. The source struct\nuses `#[serde(rename_all = \"camelCase\")]`; this mirror preserves it.",
        "required": [
          "coinId",
          "ticker",
          "atomicUnitsPerCoin",
          "pendingAtomic",
          "confirmedAtomic",
          "submittedAtomic"
        ],
        "properties": {
          "atomicUnitsPerCoin": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "coinId": {
            "type": "string"
          },
          "confirmedAtomic": {
            "type": "string"
          },
          "pendingAtomic": {
            "type": "string"
          },
          "submittedAtomic": {
            "type": "string"
          },
          "ticker": {
            "type": "string"
          }
        }
      },
      "HealthBucket": {
        "type": "object",
        "description": "Doc-only OpenAPI schema mirror of\n`stratum_backend::worker_health_publisher::HealthBucket`.\n\npool-api receives the worker-health body as opaque `Vec<u8>` bytes over\nthe icanact mesh (it never deserializes them) and passes them through\nverbatim to the HTTP client. This struct exists ONLY so the generated\nOpenAPI spec documents the real response shape returned by `/api/v1/user`\nand `/api/v1/user/workers`. It MUST be kept in sync with the\nsource-of-truth struct in `stratum-backend`.\n\nNOTE: the source struct does NOT use `#[serde(rename_all = \"camelCase\")]`,\nso its wire JSON keys are snake_case (`ts_ms`); this mirror preserves\nthat exactly so the generated schema matches the wire.",
        "required": [
          "ts_ms",
          "online",
          "degraded",
          "offline"
        ],
        "properties": {
          "degraded": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "offline": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "online": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "ts_ms": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "PayoutRow": {
        "type": "object",
        "description": "Doc-only OpenAPI schema mirror of\n`stratum_backend::account_payouts_publisher::PayoutRow`.\n\nSee [`WorkerHealthSnapshot`] for the mirror rationale. The source struct\nuses `#[serde(rename_all = \"camelCase\")]`; this mirror preserves it.\n`status` is `String` here (schema-equivalent to the source `&'static str`).",
        "required": [
          "operationId",
          "coinId",
          "ticker",
          "atomicUnitsPerCoin",
          "amountAtomic",
          "status",
          "blockHashHex",
          "createdAtMs",
          "attemptCount"
        ],
        "properties": {
          "amountAtomic": {
            "type": "string"
          },
          "atomicUnitsPerCoin": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "attemptCount": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "blockHashHex": {
            "type": "string"
          },
          "coinId": {
            "type": "string"
          },
          "createdAtMs": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "operationId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "ticker": {
            "type": "string"
          }
        }
      },
      "PublicCoinSnapshotV1": {
        "type": "object",
        "required": [
          "schemaVersion",
          "producedUnixMs",
          "epoch",
          "sequence",
          "sourceWatermarks",
          "producerId",
          "coin",
          "history",
          "pool",
          "blocks",
          "activeStratums"
        ],
        "properties": {
          "activeStratums": {},
          "blocks": {},
          "coin": {},
          "epoch": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "history": {},
          "pool": {},
          "producedUnixMs": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "producerId": {
            "type": "string"
          },
          "schemaVersion": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "sequence": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sourceWatermarks": {}
        }
      },
      "PublicPoolSnapshotV1": {
        "type": "object",
        "required": [
          "schemaVersion",
          "producedUnixMs",
          "epoch",
          "sequence",
          "sourceWatermarks",
          "producerId",
          "contentHash",
          "catalog",
          "activeStratums",
          "histories",
          "pool",
          "blocks"
        ],
        "properties": {
          "activeStratums": {},
          "blocks": {},
          "catalog": {},
          "contentHash": {
            "type": "string"
          },
          "epoch": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "histories": {},
          "pool": {},
          "producedUnixMs": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "producerId": {
            "type": "string"
          },
          "schemaVersion": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "sequence": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "sourceWatermarks": {}
        }
      },
      "WorkerHealthSnapshot": {
        "type": "object",
        "description": "Doc-only OpenAPI schema mirror of\n`stratum_backend::worker_health_publisher::WorkerHealthSnapshot`.\n\nSee [`HealthBucket`] for the mirror rationale. Wire keys are snake_case\n(no serde camelCase on the source struct): `produced_unix_ms`.",
        "required": [
          "v",
          "produced_unix_ms",
          "buckets"
        ],
        "properties": {
          "buckets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HealthBucket"
            }
          },
          "produced_unix_ms": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "v": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      }
    },
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "api-key",
        "description": "User-created pool API key from dashboard Settings > API."
      }
    }
  },
  "tags": [
    {
      "name": "Public",
      "description": "Anonymous, cacheable public pool data."
    },
    {
      "name": "User",
      "description": "Authenticated account data."
    }
  ]
}
