{
  "openapi": "3.0.3",
  "info": {
    "title": "Unpictured API",
    "version": "1.1.0",
    "description": "Classic public-domain books read a passage at a time, with each book's cast and chapters and a link to watch it as a film on Unpictured. Signed-in users can also make things on Unpictured with their own credits: always call quote first, read the price out, and only call make after the user says yes.",
    "contact": {
      "email": "hello@askmizan.com"
    }
  },
  "servers": [
    {
      "url": "https://storyconnectors.pages.dev/books/v1"
    }
  ],
  "paths": {
    "/books": {
      "get": {
        "operationId": "listBooks",
        "summary": "The library",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/books/{id}": {
      "get": {
        "operationId": "getBook",
        "summary": "A book's cast and chapters",
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown book"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "10002"
          }
        ]
      }
    },
    "/books/{id}/chapter/{n}": {
      "get": {
        "operationId": "readChapter",
        "summary": "Read a chapter a passage at a time; follow next to keep reading",
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Chapter or part out of range"
          },
          "404": {
            "description": "Unknown book"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "10002"
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "part",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Which passage, from 1"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Paragraphs per passage, 1 to 10, default 3"
          }
        ]
      }
    },
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Service status",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "myAccount",
        "summary": "The user's Unpictured credits, daily limit and credit packs",
        "security": [
          {
            "museSignIn": [
              "credits:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/quote": {
      "post": {
        "operationId": "quote",
        "summary": "Price a make without spending anything. Read the returned say to the user and ask them to confirm.",
        "security": [
          {
            "museSignIn": [
              "credits:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kind",
                  "book"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "move_scene",
                      "speak_scene",
                      "trailer"
                    ],
                    "description": "move_scene 18 credits; speak_scene 60 credits (the quote gives the exact line and speaker); trailer 18 credits for each trailer scene not yet moving. Only the user's own film books, listed by /me."
                  },
                  "book": {
                    "type": "string",
                    "description": "Book id from /me (the user's own books)."
                  },
                  "chapter": {
                    "type": "string",
                    "description": "Chapter label, for example I."
                  },
                  "scene": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "look": {
                    "type": "string",
                    "enum": [
                      "cinematic",
                      "gentle"
                    ],
                    "description": "Moving pictures: cinematic (more action, the default) or gentle (calmer). Same price."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/make": {
      "post": {
        "operationId": "make",
        "summary": "Make it with the user's own credits. Only after the user has agreed to the quoted price; send that price as credits.",
        "security": [
          {
            "museSignIn": [
              "credits:read",
              "make"
            ]
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 80
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "type": "object",
                    "required": [
                      "kind",
                      "book"
                    ],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "move_scene",
                          "speak_scene",
                          "trailer"
                        ],
                        "description": "move_scene 18 credits; speak_scene 60 credits (the quote gives the exact line and speaker); trailer 18 credits for each trailer scene not yet moving. Only the user's own film books, listed by /me."
                      },
                      "book": {
                        "type": "string",
                        "description": "Book id from /me (the user's own books)."
                      },
                      "chapter": {
                        "type": "string",
                        "description": "Chapter label, for example I."
                      },
                      "scene": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "look": {
                        "type": "string",
                        "enum": [
                          "cinematic",
                          "gentle"
                        ],
                        "description": "Moving pictures: cinematic (more action, the default) or gentle (calmer). Same price."
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "credits"
                    ],
                    "properties": {
                      "credits": {
                        "type": "integer",
                        "description": "The exact credits from /quote that the user agreed to."
                      },
                      "idempotency_key": {
                        "type": "string",
                        "description": "Optional. Same key again returns the first job, never a second charge."
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits. Nothing started; packs has checkout links.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "Price changed or no quoted price sent. Quote again and ask the user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{job_id}": {
      "get": {
        "operationId": "job",
        "summary": "Progress of a make; when done, the link and video, images or text. Failed makes are refunded automatically.",
        "security": [
          {
            "museSignIn": [
              "credits:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cap": {
      "post": {
        "operationId": "setDailyLimit",
        "summary": "Set the user's own daily credit limit for Muse (0 to 5000).",
        "security": [
          {
            "museSignIn": [
              "credits:read",
              "make"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "daily_credits"
                ],
                "properties": {
                  "daily_credits": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Plain-sentence error, safe to read out",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "museSignIn": {
        "type": "oauth2",
        "description": "The user signs in to their own Unpictured account. Only their own credits are spent.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://unpictured.app/oauth/authorize",
            "tokenUrl": "https://unpictured.app/oauth/token",
            "refreshUrl": "https://unpictured.app/oauth/token",
            "scopes": {
              "credits:read": "See your credits",
              "make": "Make things with your credits"
            }
          }
        }
      }
    }
  }
}