{
  "openapi": "3.1.0",
  "info": {
    "title": "BunCho API",
    "version": "1.0.0",
    "summary": "日本語の物語・漫画・縦型ショート動画を、完成品まで 1 回の呼び出しで返す API",
    "description": "小説・台本の生成、4コマ・漫画、縦型ショート動画、設定集 (story bible)、矛盾の確認。既定は BunCho 独自モデル。料金は DREAM (DREAM パックを Stripe で購入)。文書: https://bun-cho.work/developers",
    "contact": {
      "url": "https://bun-cho.work/developers"
    },
    "termsOfService": "https://bun-cho.work/terms#api"
  },
  "servers": [
    {
      "url": "https://bun-cho.work/studio/api/v1"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "bk_live_... (Studio の設定 → API 鍵で発行)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "purchase_url": {
                "type": "string"
              },
              "available_dream": {
                "type": "number"
              },
              "required_dream": {
                "type": "number"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        }
      },
      "Dream": {
        "type": "object",
        "properties": {
          "charged": {
            "type": "number"
          },
          "list": {
            "type": "number"
          },
          "campaign_discount": {
            "type": "number"
          },
          "floor": {
            "type": "number"
          }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "job"
          },
          "type": {
            "type": "string"
          },
          "status": {
            "enum": [
              "queued",
              "running",
              "done",
              "failed"
            ]
          },
          "stage": {
            "type": [
              "string",
              "null"
            ]
          },
          "result": {
            "type": [
              "object",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "dream": {
            "type": "object"
          }
        }
      }
    }
  },
  "paths": {
    "/models": {
      "get": {
        "operationId": "listModels",
        "summary": "モデルの一覧 (OpenAI 互換)",
        "responses": {
          "200": {
            "description": "一覧",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "summary": "OpenAI 互換の chat completions (base_url を差し替えるだけ)",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "messages"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "既定 buncho-creative (BunCho 独自モデル)。外部のモデルを明示すると、その分は公表単価 × 3 (キャンペーン対象外)",
                    "example": "buncho-creative"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "role": {
                          "enum": [
                            "system",
                            "developer",
                            "user",
                            "assistant"
                          ]
                        },
                        "content": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "max_tokens": {
                    "type": "integer"
                  },
                  "temperature": {
                    "type": "number"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "chat.completion (stream: true なら text/event-stream)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/novel": {
      "post": {
        "operationId": "writeNovel",
        "summary": "小説・台本を書く (write: アイデア → 短編 / episode: あらすじ → 第 1 話 / continue: 続き / revise: 直し / script: 縦型ショートドラマの台本)。同期",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "mode": {
                    "enum": [
                      "write",
                      "episode",
                      "continue",
                      "revise",
                      "script"
                    ]
                  },
                  "text": {
                    "type": "string",
                    "maxLength": 60000
                  },
                  "instruction": {
                    "type": "string"
                  },
                  "length": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 8000,
                    "description": "書く字数の目安 (既定 1000)"
                  },
                  "style": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string",
                    "description": "出力の言語 (BCP 47。例 ja, en, ko, zh-Hant, es, fr, hi, ar)。省略・auto は入力の言語に合わせる",
                    "example": "ja"
                  },
                  "model": {
                    "type": "string",
                    "description": "既定 buncho-creative (BunCho 独自モデル)。外部のモデルを明示すると、その分は公表単価 × 3 (キャンペーン対象外)",
                    "example": "buncho-creative"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, text, chars, usage, dream }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/story-bible": {
      "post": {
        "operationId": "storyBible",
        "summary": "原稿 → 設定集 (人物・関係・年表・用語・伏線)。同期",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string",
                    "description": "出力の言語 (BCP 47。例 ja, en, ko, zh-Hant, es, fr, hi, ar)。省略・auto は入力の言語に合わせる",
                    "example": "ja"
                  },
                  "model": {
                    "type": "string",
                    "description": "既定 buncho-creative (BunCho 独自モデル)。外部のモデルを明示すると、その分は公表単価 × 3 (キャンペーン対象外)",
                    "example": "buncho-creative"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "設定集",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/check": {
      "post": {
        "operationId": "checkStory",
        "summary": "原稿の矛盾と回収していない伏線 (引用は原稿にあるものだけ)。同期",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string",
                    "description": "出力の言語 (BCP 47。例 ja, en, ko, zh-Hant, es, fr, hi, ar)。省略・auto は入力の言語に合わせる",
                    "example": "ja"
                  },
                  "model": {
                    "type": "string",
                    "description": "既定 buncho-creative (BunCho 独自モデル)。外部のモデルを明示すると、その分は公表単価 × 3 (キャンペーン対象外)",
                    "example": "buncho-creative"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ issues, open_foreshadowing }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/manga": {
      "post": {
        "operationId": "createManga",
        "summary": "1 行・あらすじ・原稿 → 4コマ / 漫画の画像 (job)。台詞の言語: ja, en, es, pt, zh-Hant, ko, zh-Hans",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "format": {
                    "enum": [
                      "4koma",
                      "page",
                      "webtoon"
                    ]
                  },
                  "quality": {
                    "enum": [
                      "own_gpu",
                      "standard",
                      "high",
                      "premium"
                    ],
                    "description": "既定 own_gpu (自社 GPU・いちばん安い)"
                  },
                  "strips": {
                    "type": "integer"
                  },
                  "pages": {
                    "type": "integer"
                  },
                  "language": {
                    "type": "string",
                    "description": "出力の言語 (BCP 47。例 ja, en, ko, zh-Hant, es, fr, hi, ar)。省略・auto は入力の言語に合わせる",
                    "example": "ja",
                    "enum": [
                      "ja",
                      "en",
                      "es",
                      "pt",
                      "zh-Hant",
                      "ko",
                      "zh-Hans",
                      "auto"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/video": {
      "post": {
        "operationId": "createVideo",
        "summary": "台本・あらすじ → 縦型ショート動画 mp4 (job: 絵コンテ → 書き出し)。字幕の言語: ja, en, es, pt, zh-Hant, ko, zh-Hans",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 100
            },
            "description": "同じキーの 2 回目は前の結果を返す (二重に引かない)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "aspect": {
                    "enum": [
                      "9:16",
                      "16:9",
                      "1:1"
                    ]
                  },
                  "language": {
                    "type": "string",
                    "description": "出力の言語 (BCP 47。例 ja, en, ko, zh-Hant, es, fr, hi, ar)。省略・auto は入力の言語に合わせる",
                    "example": "ja",
                    "enum": [
                      "ja",
                      "en",
                      "es",
                      "pt",
                      "zh-Hant",
                      "ko",
                      "zh-Hans",
                      "auto"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "DREAM が足りない (purchase_url 付き)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "内容の判定で止めた (未成年・実在の人物・性的・違法)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "回数・同時の数・1 日の上限、または独自モデルが混んでいる (Retry-After)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}": {
      "get": {
        "operationId": "getJob",
        "summary": "job の状態と結果 (画像・動画の URL)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "404": {
            "description": "無い",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/estimate": {
      "post": {
        "operationId": "estimate",
        "summary": "見積もり (無料): 値段 (DREAM・円の目安) と残高",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "action"
                ],
                "properties": {
                  "action": {
                    "enum": [
                      "novel",
                      "story_bible",
                      "check",
                      "chat",
                      "manga",
                      "video"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "length": {
                    "type": "integer"
                  },
                  "model": {
                    "type": "string",
                    "description": "既定 buncho-creative (BunCho 独自モデル)。外部のモデルを明示すると、その分は公表単価 × 3 (キャンペーン対象外)",
                    "example": "buncho-creative"
                  },
                  "format": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "見積もり",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "鍵が無い・正しくない・止められている",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/balance": {
      "get": {
        "operationId": "balance",
        "summary": "残高と、この鍵の今日の使用量・上限 (無料)",
        "responses": {
          "200": {
            "description": "残高",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/pricing": {
      "get": {
        "operationId": "pricing",
        "summary": "値段の表 (鍵なしで読める)",
        "security": [],
        "responses": {
          "200": {
            "description": "値段の表",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "x-webhooks": {
    "job.done": {
      "description": "鍵に webhook の URL を置くと、job が終わったとき POST する。署名: BunCho-Signature: t=<秒>,v1=HMAC-SHA256(webhook の秘密, \"<秒>.<本文>\")"
    }
  }
}
