{
  "openapi": "3.0.3",
  "info": {
    "title": "HSI Reclaim Debit — Ledger API",
    "version": "1.6.0",
    "description": "State ledger + v1.6 work-order orchestrator for the HSI Reclaim Debit playbook. Stores state only; never trades. Human transmits on IB. All times HKT. Reason priority: position_open > cool_off > outside_day_session > ok. Day session: 09:30-12:00 & 13:00-16:00 HKT (lunch = no entries)."
  },
  "servers": [
    {
      "url": "https://playbook.db3hk.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/ledger/status": {
      "get": {
        "summary": "Entry gate — call FIRST before any GO",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/ledger": {
      "get": {
        "summary": "Full ledger JSON",
        "responses": {
          "200": {
            "description": "Ledger",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ledger"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "put": {
        "summary": "Replace ledger (manual reconciliation)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Ledger"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "422": {
            "description": "schema_version_mismatch (expected 1.6)"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/check": {
      "post": {
        "summary": "Single trigger — returns NO-GO or a v1.6 work order (never trades). Day session 09:30-12:00 & 13:00-16:00 HKT Mon-Fri excl. configured HKEX holidays.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "book",
                  "target",
                  "horizon",
                  "side"
                ],
                "properties": {
                  "book": {
                    "type": "string",
                    "example": "Tactical"
                  },
                  "target": {
                    "type": "number",
                    "example": 25500
                  },
                  "horizon": {
                    "type": "string",
                    "example": "tomorrow"
                  },
                  "side": {
                    "type": "string",
                    "enum": [
                      "bull_call",
                      "bear_put"
                    ],
                    "example": "bull_call"
                  },
                  "vhsi": {
                    "type": "number",
                    "example": 18.5
                  },
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "NO-GO {ok:false, decision:'NO-GO', reason} or work order {ok:true, steps[6], playbook:'v1.6'}"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "missing_fields (validated before the session/state gate)"
          }
        }
      }
    },
    "/ledger/open": {
      "post": {
        "summary": "Record a fill (sets open_position)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Position"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Opened"
          },
          "409": {
            "description": "position_already_open"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/ledger/close": {
      "post": {
        "summary": "Record an exit; enforces cool-off (stop always; scratch <= -15%)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "result",
                  "pnl_pct"
                ],
                "properties": {
                  "result": {
                    "type": "string",
                    "enum": [
                      "tp",
                      "stop",
                      "scratch",
                      "manual"
                    ]
                  },
                  "pnl_pct": {
                    "type": "number",
                    "example": -40
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Closed; returns last_closed + cool_off_until"
          },
          "400": {
            "description": "invalid_result"
          },
          "409": {
            "description": "no_open_position"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/manage": {
      "post": {
        "summary": "Manage open position — never suggests new entries",
        "responses": {
          "200": {
            "description": "Position + reminders, or {ok:false, reason:'flat'}"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing/wrong bearer token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string"
          }
        }
      },
      "Status": {
        "type": "object",
        "properties": {
          "can_new_entry": {
            "type": "boolean"
          },
          "reason": {
            "type": "string",
            "enum": [
              "ok",
              "outside_day_session",
              "position_open",
              "cool_off"
            ]
          },
          "cool_off_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "has_open": {
            "type": "boolean"
          },
          "in_day_session": {
            "type": "boolean"
          },
          "now_hkt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Position": {
        "type": "object",
        "description": "Stored verbatim as open_position; entry_time_hkt added if absent",
        "properties": {
          "book": {
            "type": "string"
          },
          "side": {
            "type": "string"
          },
          "expiry": {
            "type": "string",
            "format": "date"
          },
          "long_strike": {
            "type": "number"
          },
          "short_strike": {
            "type": "number"
          },
          "width": {
            "type": "number"
          },
          "entry_debit_pts": {
            "type": "number"
          },
          "entry_debit_hkd": {
            "type": "number"
          },
          "named_level": {
            "type": "number"
          },
          "horizon": {
            "type": "string"
          },
          "stop_debit_pts": {
            "type": "number"
          },
          "lower_tp_debit_pts": {
            "type": "number"
          },
          "washout_low": {
            "type": "number"
          },
          "washout_high": {
            "type": "number"
          },
          "remaining_dte_at_entry": {
            "type": "integer"
          }
        }
      },
      "Ledger": {
        "type": "object",
        "properties": {
          "schema_version": {
            "type": "string",
            "example": "1.6"
          },
          "account_hkd": {
            "type": "number",
            "example": 10000
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "cool_off_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "cool_off_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "open_position": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Position"
              },
              {
                "type": "null"
              }
            ]
          },
          "last_closed": {
            "type": [
              "object",
              "null"
            ]
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}