{
  "openapi": "3.1.0",
  "info": {
    "title": "Wenbu · 问卜",
    "version": "1.1.0",
    "description": "Free, transparent cultural calculation tools. No predictive validity claims.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    }
  },
  "servers": [
    {
      "url": "https://wenbu.genedai.me"
    }
  ],
  "paths": {
    "/api/v1/bazi": {
      "post": {
        "operationId": "calculate_bazi",
        "summary": "Calculate or draw bazi symbols",
        "description": "No authentication. Cultural reflection, not established prediction. JSON body capped at 8192 bytes. Rate limits apply.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "date": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Gregorian date, 1901–2099"
                  },
                  "time": {
                    "anyOf": [
                      {
                        "type": "string",
                        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "default": null
                  },
                  "timezone": {
                    "type": "string",
                    "default": "Asia/Shanghai",
                    "maxLength": 80
                  },
                  "dayBoundary": {
                    "type": "string",
                    "enum": [
                      "midnight",
                      "zi"
                    ],
                    "default": "midnight"
                  },
                  "solarTime": {
                    "type": "boolean",
                    "default": false
                  },
                  "longitude": {
                    "type": "number",
                    "minimum": -180,
                    "maximum": 180
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  }
                },
                "required": [
                  "date"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured result including method and conventions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "kind",
                    "version",
                    "method"
                  ],
                  "properties": {
                    "kind": {
                      "const": "bazi"
                    },
                    "version": {
                      "type": "string"
                    },
                    "method": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON"
          },
          "403": {
            "description": "Browser origin rejected"
          },
          "413": {
            "description": "Request too large"
          },
          "415": {
            "description": "JSON content type required"
          },
          "422": {
            "description": "Invalid input or ambiguous date/time"
          },
          "429": {
            "description": "Request limit reached"
          }
        }
      }
    },
    "/api/v1/ziwei": {
      "post": {
        "operationId": "calculate_ziwei",
        "summary": "Calculate or draw ziwei symbols",
        "description": "No authentication. Cultural reflection, not established prediction. JSON body capped at 8192 bytes. Rate limits apply.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "date": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Gregorian date, 1901–2099"
                  },
                  "time": {
                    "type": "string",
                    "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                  },
                  "sex": {
                    "type": "string",
                    "enum": [
                      "male",
                      "female"
                    ]
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  }
                },
                "required": [
                  "date",
                  "time",
                  "sex"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured result including method and conventions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "kind",
                    "version",
                    "method"
                  ],
                  "properties": {
                    "kind": {
                      "const": "ziwei"
                    },
                    "version": {
                      "type": "string"
                    },
                    "method": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON"
          },
          "403": {
            "description": "Browser origin rejected"
          },
          "413": {
            "description": "Request too large"
          },
          "415": {
            "description": "JSON content type required"
          },
          "422": {
            "description": "Invalid input or ambiguous date/time"
          },
          "429": {
            "description": "Request limit reached"
          }
        }
      }
    },
    "/api/v1/iching": {
      "post": {
        "operationId": "cast_iching",
        "summary": "Calculate or draw iching symbols",
        "description": "No authentication. Cultural reflection, not established prediction. JSON body capped at 8192 bytes. Rate limits apply.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "lines": {
                    "type": "array",
                    "minItems": 6,
                    "maxItems": 6,
                    "items": {
                      "type": "integer",
                      "enum": [
                        6,
                        7,
                        8,
                        9
                      ]
                    },
                    "description": "Bottom to top. Omit for cryptographic random three-coin casting."
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured result including method and conventions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "kind",
                    "version",
                    "method"
                  ],
                  "properties": {
                    "kind": {
                      "const": "iching"
                    },
                    "version": {
                      "type": "string"
                    },
                    "method": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON"
          },
          "403": {
            "description": "Browser origin rejected"
          },
          "413": {
            "description": "Request too large"
          },
          "415": {
            "description": "JSON content type required"
          },
          "422": {
            "description": "Invalid input or ambiguous date/time"
          },
          "429": {
            "description": "Request limit reached"
          }
        }
      }
    },
    "/api/v1/tarot": {
      "post": {
        "operationId": "draw_tarot",
        "summary": "Calculate or draw tarot symbols",
        "description": "No authentication. Cultural reflection, not established prediction. JSON body capped at 8192 bytes. Rate limits apply.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "count": {
                    "type": "integer",
                    "enum": [
                      1,
                      3
                    ],
                    "default": 3
                  },
                  "reversals": {
                    "type": "boolean",
                    "default": true
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured result including method and conventions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "kind",
                    "version",
                    "method"
                  ],
                  "properties": {
                    "kind": {
                      "const": "tarot"
                    },
                    "version": {
                      "type": "string"
                    },
                    "method": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON"
          },
          "403": {
            "description": "Browser origin rejected"
          },
          "413": {
            "description": "Request too large"
          },
          "415": {
            "description": "JSON content type required"
          },
          "422": {
            "description": "Invalid input or ambiguous date/time"
          },
          "429": {
            "description": "Request limit reached"
          }
        }
      }
    },
    "/api/v1/interpret": {
      "post": {
        "operationId": "interpret_reading",
        "summary": "Optional metered AI interpretation",
        "description": "User must explicitly consent. Recomputes supplied chart data. Five attempts per network per Shanghai day; global budget 1000 attempts. Upstream attempts count even if they fail. Tarot input is cards [{id:0..77,reversed:boolean}] with 1 or 3 unique cards. Other inputs follow their calculation schema; I Ching requires the original lines.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "bazi",
                      "ziwei",
                      "iching",
                      "tarot"
                    ]
                  },
                  "input": {
                    "type": "object"
                  },
                  "question": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 600
                  },
                  "context": {
                    "type": "string",
                    "maxLength": 1600,
                    "default": ""
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  },
                  "consent": {
                    "const": true
                  }
                },
                "required": [
                  "kind",
                  "input",
                  "question",
                  "consent"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validated structured interpretation, remaining allowance and requested/served model provenance"
          },
          "422": {
            "description": "Invalid input or missing consent"
          },
          "429": {
            "description": "Daily allowance or global budget reached"
          },
          "502": {
            "description": "Incomplete upstream response"
          },
          "503": {
            "description": "AI unavailable"
          }
        }
      }
    },
    "/api/v1/agent": {
      "post": {
        "operationId": "run_agent_turn",
        "summary": "Run one bounded DeepSeek Agent turn with real tools and streamed artifacts",
        "description": "Explicit consent to send selected context to DeepSeek. No server-side conversation history. Body <=98304 bytes. Twelve turns/network/Shanghai day; at most five model calls and 12 tool executions per turn, 120-second deadline. Shared site model budget 1000, Agent sub-budget 600. Each attempted model call counts, including failures. Research covers a curated catalogue, not unrestricted web search. Stream errors can occur after HTTP 200: only a done event confirms terminal status; waiting and limited are not complete.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "message": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 3000
                  },
                  "consent": {
                    "const": true
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "zh",
                      "en"
                    ],
                    "default": "zh"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "explore",
                      "research"
                    ],
                    "default": "explore"
                  },
                  "newDraw": {
                    "type": "boolean",
                    "default": false,
                    "description": "True only after the user explicitly requests a new random result."
                  },
                  "history": {
                    "type": "array",
                    "maxItems": 16,
                    "description": "At most 28000 characters combined; never system or tool roles.",
                    "items": {
                      "type": "object",
                      "additionalProperties": false,
                      "properties": {
                        "role": {
                          "enum": [
                            "user",
                            "assistant"
                          ]
                        },
                        "content": {
                          "type": "string",
                          "maxLength": 7000
                        }
                      },
                      "required": [
                        "role",
                        "content"
                      ]
                    }
                  },
                  "context": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "note": {
                        "type": "string",
                        "maxLength": 5000,
                        "default": ""
                      },
                      "reports": {
                        "type": "array",
                        "maxItems": 2,
                        "description": "Prior drafts for revision, never verified evidence. Combined summary/section headings/bodies/questions <=1800 characters per report.",
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "title": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 100
                            },
                            "summary": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 450
                            },
                            "sections": {
                              "type": "array",
                              "minItems": 1,
                              "maxItems": 4,
                              "items": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                  "heading": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 100
                                  },
                                  "body": {
                                    "type": "string",
                                    "minLength": 1,
                                    "maxLength": 700
                                  },
                                  "sourceIds": {
                                    "type": "array",
                                    "maxItems": 6,
                                    "items": {
                                      "type": "string",
                                      "maxLength": 120
                                    }
                                  }
                                },
                                "required": [
                                  "heading",
                                  "body"
                                ]
                              }
                            },
                            "questions": {
                              "type": "array",
                              "maxItems": 3,
                              "items": {
                                "type": "string",
                                "maxLength": 100
                              }
                            }
                          },
                          "required": [
                            "title",
                            "summary",
                            "sections"
                          ]
                        }
                      },
                      "birth": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                          "date": {
                            "type": "string",
                            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                            "description": "Gregorian date, 1901–2099"
                          },
                          "time": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "timezone": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 80
                          },
                          "dayBoundary": {
                            "enum": [
                              "midnight",
                              "zi"
                            ]
                          },
                          "solarTime": {
                            "type": "boolean"
                          },
                          "longitude": {
                            "type": "number",
                            "minimum": -180,
                            "maximum": 180
                          },
                          "sex": {
                            "enum": [
                              "male",
                              "female"
                            ]
                          }
                        },
                        "required": [
                          "date",
                          "time",
                          "timezone",
                          "dayBoundary",
                          "solarTime"
                        ]
                      },
                      "readings": {
                        "type": "array",
                        "maxItems": 6,
                        "items": {
                          "type": "object",
                          "additionalProperties": false,
                          "properties": {
                            "kind": {
                              "enum": [
                                "bazi",
                                "ziwei",
                                "iching",
                                "tarot"
                              ]
                            },
                            "input": {
                              "description": "Original calculation input. For I Ching, original six lines required; for tarot, original cards [{id:0..77,reversed:boolean}], 1 or 3 unique cards."
                            }
                          },
                          "required": [
                            "kind",
                            "input"
                          ]
                        }
                      },
                      "sourceIds": {
                        "type": "array",
                        "maxItems": 12,
                        "items": {
                          "type": "string",
                          "maxLength": 120
                        },
                        "description": "Known source IDs are verified again. A client-provided ID never establishes that an external source was read."
                      }
                    },
                    "required": []
                  }
                },
                "required": [
                  "message",
                  "consent"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE JSON events: start, delta, tool_start, tool_end, plan, source, artifact, question, context, error, done. See /agent-protocol.md. Hidden model reasoning is never emitted.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "Browser origin rejected"
          },
          "413": {
            "description": "Body exceeds 96 KiB"
          },
          "422": {
            "description": "Invalid request, missing consent or invalid original chart context"
          },
          "429": {
            "description": "Network or shared daily limit reached"
          },
          "503": {
            "description": "Model or quota configuration unavailable"
          }
        }
      }
    }
  }
}
