{
  "openapi": "3.1.0",
  "info": {
    "title": "Dabble Connect API",
    "version": "3.1.0-beta.48",
    "description": "The Dabble Connect API gives an integration the same access to an author's Dabble projects that a connected AI app has: read everything, add to and edit the planning documents, reorganise the manuscript (add, rename, move and remove its parts, chapters and scenes), and never change a word of the manuscript. That last line is enforced by the server, not by convention: manuscript text is read-only in every operation here, and a scene the API adds starts empty.\n\n## Authentication\n\nEvery request carries a bearer token in the `Authorization` header. Two kinds are accepted:\n\n- **OAuth 2.1** access tokens (authorization code with PKCE; dynamic client registration is supported). Ask for the scopes the integration needs; the author chooses at consent whether to grant `planning:write`, `images:write` and `manuscript:suggest` (Track Changes, off unless the author ticks it, and only alongside `planning:write`).\n- **API keys** an author creates on their Connected Apps page, for scripts and tools the author runs themselves. An API key carries the scopes chosen when it was made.\n\nThe account behind the credential must hold an active Dabble subscription that includes Connect; otherwise every request answers 403 `subscription_required`.\n\n## Attribution\n\nEvery write is recorded against the account whose token or key made it, and marked as made through the API: the change carries `source: \"api\"` beside the author (the MCP server writes `mcp`), set by the server rather than the caller. Notes and comments an integration adds carry the same mark, and Dabble shows them as made by the app rather than by the author.\n\n## Conventions\n\n- Bodies are JSON both ways. Success responses return the operation's response schema and nothing else; errors return the `Error` schema with a machine-readable `error` code and a message written for the person using the integration.\n- Arguments the server does not know are rejected with 400 rather than dropped, so a misspelt field cannot silently discard data.\n- Long texts are paginated by character offset: pass the returned `nextOffset` to continue. A manuscript read also returns the project's `rev`; pass it back so a continuation is refused, rather than misread, if the project changed in between.\n- Writes are attributed to the author, stamped as coming from your integration, and appear in Dabble labelled \"Dabble Connect\".\n- Send an `Idempotency-Key` header on a write to make it safe to retry: the first response is stored for 24 hours and replayed for a repeat of the same request with the same key (the replay carries `Idempotent-Replayed: true`).\n- Rate limits: requests per minute per credential, and writes per project (30 a minute, 300 an hour, 1,000 a day per author and project). Images have their own, smaller budget (10 a minute, 60 an hour, 200 a day per author and project). A 429 carries `Retry-After`.\n- An image is given as a public `https` link. Dabble fetches it once, keeps its own copy, and stores that copy's address on the document: PNG, JPEG, WebP or GIF, up to 5 MB.\n\n## Errors\n\n| `error`                 | Status | Meaning                                                                                  |\n| ----------------------- | ------ | ---------------------------------------------------------------------------------------- |\n| `invalid`               | 400    | Malformed request or an argument failed validation (`details` lists the issues).        |\n| `unauthorized`          | 401    | No credential, or one that is invalid, expired, or revoked.                              |\n| `insufficient_scope`    | 403    | The credential was not granted the scope this operation needs.                           |\n| `subscription_required` | 403    | The account has no Dabble subscription with Connect.                                     |\n| `feature_unavailable`   | 403    | The account's plan does not include the feature behind this operation.                  |\n| `forbidden`             | 403    | Your role on the project does not allow this.                                            |\n| `not_found`             | 404    | No such project, document, or endpoint.                                                  |\n| `too_large`             | 413    | The change is too large for Dabble to store in one piece.                                |\n| `limit`                 | 429    | A rate limit was hit.                                                                    |\n| `internal`              | 500    | Dabble Connect hit an unexpected error.                                                  |\n| `upstream`              | 502    | The Dabble sync service answered with an error.                                          |\n| `unavailable`           | 503    | Dabble is temporarily unavailable.                                                       |",
    "contact": {
      "name": "Dabble",
      "url": "https://www.dabblewriter.com"
    }
  },
  "servers": [
    {
      "url": "https://connect.dabblewriter.com/v1",
      "description": "Dabble Connect"
    }
  ],
  "tags": [
    {
      "name": "core",
      "description": "The account and its projects: listing, the outline, search, labels, moving documents."
    },
    {
      "name": "manuscripts",
      "description": "Manuscript text and summaries. Text is read-only by design."
    },
    {
      "name": "highlight",
      "description": "Highlights on manuscript text: formatting on a range, never a change to the words. Requires the `highlight` feature on the account's plan."
    },
    {
      "name": "plots",
      "description": "Plot grids, their lines and points. Requires the `plotting` feature on the account's plan."
    },
    {
      "name": "timeline",
      "description": "Requires the `timeline` feature on the account's plan."
    },
    {
      "name": "characters",
      "description": "Casts, characters and their sheets. Requires the `characters` feature on the account's plan."
    },
    {
      "name": "family-trees",
      "description": "Requires the `family_trees` feature on the account's plan."
    },
    {
      "name": "hierarchies",
      "description": "Requires the `hierarchies` feature on the account's plan."
    },
    {
      "name": "locations",
      "description": "Requires the `locations` feature on the account's plan."
    },
    {
      "name": "notebook",
      "description": "The notebook: folders and pages. Requires the `notebook` feature on the account's plan."
    },
    {
      "name": "ideas",
      "description": "The author’s Ideas notebook, a project of its own. Requires the `notebook` feature on the account's plan."
    },
    {
      "name": "images",
      "description": "Portraits and banners on documents, and the account’s image library."
    },
    {
      "name": "notes",
      "description": "Note cards attached to any document. Requires the `notes` feature on the account's plan."
    },
    {
      "name": "comments",
      "description": "Comment threads on manuscript text. Requires the `comments` feature on the account's plan."
    },
    {
      "name": "track-changes",
      "description": "Requires the `track_changes` feature on the account's plan."
    },
    {
      "name": "goals",
      "description": "Word-count goals and writing history. Requires the `goals` feature on the account's plan."
    },
    {
      "name": "versioning",
      "description": "Version history: what a document held at a saved version, and copying it forward. Requires the `versioning` feature on the account's plan."
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "operationId": "dabble_whoami",
        "summary": "Who am I",
        "description": "Confirm which Dabble account this connection acts as, the app it was granted to, and the scopes it holds. Call this first if you are unsure whether the connection is working.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleWhoamiResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read"
      }
    },
    "/projects": {
      "get": {
        "operationId": "dabble_list_projects",
        "summary": "List projects",
        "description": "List the author's Dabble projects with their ids, types, your role on each, and the books inside. Call this to find the project id other tools need. Active projects are listed by default; archived, trashed, and template projects only when asked.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleListProjectsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "includeArchived",
            "in": "query",
            "required": false,
            "description": "Also list archived projects.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "includeTrashed",
            "in": "query",
            "required": false,
            "description": "Also list projects in the trash.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "includeTemplates",
            "in": "query",
            "required": false,
            "description": "Also list the author’s saved templates.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many projects to list, most recently opened first. Defaults to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ]
      }
    },
    "/projects/{projectId}/outline": {
      "get": {
        "operationId": "dabble_get_outline",
        "summary": "Get the project outline",
        "description": "The map of a project: every book, part, chapter and scene with ids, word counts, summaries, labels, note and comment counts; then the plot grids, casts, and notebook with ids. Call this before reading scenes so you fetch only what you need.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleGetOutlineResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view"
      }
    },
    "/projects/{projectId}/search": {
      "get": {
        "operationId": "dabble_search",
        "summary": "Search a project",
        "description": "Find text anywhere in a project: scenes, summaries, note cards, notebook pages, character sheets and titles. Literal text, case-insensitive by default, whole-word optional. Returns snippets with doc ids so you can read the exact scene next. Ideal for continuity checks (\"eye color\", a character name, a place).",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleSearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "The text to find, matched literally.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 500
            }
          },
          {
            "name": "caseSensitive",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "wholeWord",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "bookId",
            "in": "query",
            "required": false,
            "description": "Only search manuscript docs inside this book.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "types",
            "in": "query",
            "required": false,
            "description": "Only these doc types: the `type` values the outline and search results report.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum matches (default 50).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "x-dabble-capability": "view"
      }
    },
    "/projects/{projectId}/labels": {
      "get": {
        "operationId": "dabble_list_labels",
        "summary": "List labels",
        "description": "List the labels in use across a project (text and colour) with how many docs and notes carry each, so a new label can reuse an existing one.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleListLabelsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view"
      }
    },
    "/projects/{projectId}/docs/{docId}/label": {
      "put": {
        "operationId": "dabble_set_label",
        "summary": "Label a doc",
        "description": "Add a label (short text and/or colour) to a scene, chapter, character, plot point, or notebook page. A doc can wear several labels; this adds to them, or with replace makes this its only label. With clear, takes the given label off (or every label, when no text or colour is given). Check dabble_list_labels first to reuse an existing label; use dabble_update_label to rename or recolour one everywhere.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleSetLabelResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DabbleSetLabelRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/labels/update": {
      "post": {
        "operationId": "dabble_update_label",
        "summary": "Rename or recolour a label",
        "description": "Rename and/or recolour a label everywhere it is used: on every doc and note card that wears it and in the project label list, as the Label Manager does. Identify the label by its current text and colour from dabble_list_labels.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleUpdateLabelResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DabbleUpdateLabelRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/labels/delete": {
      "post": {
        "operationId": "dabble_delete_label",
        "summary": "Delete a label",
        "description": "Take a label out of circulation: remove it from every doc and note card that wears it and from the project label list. The docs and notes themselves are untouched. Confirm with the author first.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleDeleteLabelResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-destructive": true,
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DabbleDeleteLabelRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/move": {
      "post": {
        "operationId": "dabble_move_doc",
        "summary": "Move a document",
        "description": "Move a notebook page or folder, an image page, a character, a cast, or a place into a folder, character, place, cast, family tree, hierarchy, or section, or to a new position among its siblings: a character back out of a cast into the Characters section, a place out of another place to the top of Locations; in the Ideas notebook, move an idea or a folder between folders and the root. In the manuscript, move a scene to another chapter or blank section, a chapter or blank section to another book or part, a part to another book, or reorder books; linked plot grids follow the new scene order when the author next opens them. Pass parentId for the destination (omit to reorder in place) and position for where it lands, 1 being first (omit for the end). Nothing moves into or out of the manuscript — an image page under a chapter stays there; plot points move with plot_move_point.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleMoveDocResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id from dabble_get_outline, notebook_get_tree, character_list, or location_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DabbleMoveDocRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/icon-overlay": {
      "put": {
        "operationId": "dabble_set_icon_overlay",
        "summary": "Set an icon overlay",
        "description": "Put a small status badge on a doc's icon in the navigation (check, remove, eye, edit, or lock), or clear it with none. Works on scenes, chapters, books, characters, pages, plot grids and points.",
        "tags": [
          "core"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DabbleSetIconOverlayResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DabbleSetIconOverlayRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/manuscript/{docId}": {
      "get": {
        "operationId": "manuscript_read",
        "summary": "Read manuscript text",
        "description": "Read the text of a scene, or of a whole chapter, part, or book (its scenes in order with headings). Returns Markdown by default. Long text is paginated: pass the returned nextOffset and rev to continue; if the project changed in between, the read is refused so a continuation never skips or repeats text, and you start again from offset 0. Prefer dabble_get_outline and dabble_search to find the right scene first; a whole book is far larger than one call should fetch.",
        "tags": [
          "manuscripts"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManuscriptReadResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Id of a scene, chapter, part, or book from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "markdown (default) keeps headings and emphasis; text is plain.",
            "schema": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "When tracked changes are pending: final (default) shows the text as if accepted; original as if rejected.",
            "schema": {
              "type": "string",
              "enum": [
                "final",
                "original"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Character offset to start from (from a previous nextOffset).",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum characters per page (default 12000).",
            "schema": {
              "type": "integer",
              "minimum": 500,
              "maximum": 60000
            }
          },
          {
            "name": "rev",
            "in": "query",
            "required": false,
            "description": "The rev returned with the previous page. Continuations are refused when the project has moved on.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "x-dabble-capability": "view"
      },
      "patch": {
        "operationId": "manuscript_rename",
        "summary": "Rename a book, part, chapter or scene",
        "description": "Rename a book, part, chapter, blank section, or scene, or set a book's subtitle. An empty title clears the name, so Dabble shows its own again: a chapter's number, or a scene's opening line.",
        "tags": [
          "manuscripts"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManuscriptRenameResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Book, part, chapter, blank section, or scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManuscriptRenameRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "manuscript_remove",
        "summary": "Remove a part, chapter or scene",
        "description": "Move a part, chapter, blank section, or scene to the trash, with everything inside it, as Delete does in Dabble. Its text goes with it, unchanged, and Dabble can restore it from the trash. Confirm with the author first. Whole books stay where they are: the author trashes a book in Dabble.",
        "tags": [
          "manuscripts"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManuscriptRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Part, chapter, blank section, or scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/docs/{docId}/summary": {
      "put": {
        "operationId": "manuscript_set_summary",
        "summary": "Set a summary",
        "description": "Write the summary of a scene, chapter, part, or book: the synopsis shown on its card, in the plot grid, and in the outline. Replaces any existing summary. Plain text or light Markdown. The manuscript text itself is never changed.",
        "tags": [
          "manuscripts"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManuscriptSetSummaryResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene, chapter, part, or book id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManuscriptSetSummaryRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/manuscript": {
      "post": {
        "operationId": "manuscript_create",
        "summary": "Add a part, chapter or scene",
        "description": "Add a part, chapter, blank section, or scene to a book, empty and ready for the author to write. A scene goes in a chapter or blank section; a chapter or blank section in a book or part; a part in a book. As in Dabble, a new part starts with one chapter holding one scene, and a new chapter or blank section with one scene, or with the scenes you list (titles and summaries only). Scene text is the author's: nothing here writes it. Pass position for where it lands among its siblings, 1 being first (omit for the end). Linked plot grids pick up new scenes when the author next opens them.",
        "tags": [
          "manuscripts"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ManuscriptCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManuscriptCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/manuscript/{docId}/highlights": {
      "get": {
        "operationId": "highlight_list",
        "summary": "List highlights",
        "description": "List the highlighted passages in a scene, or in every scene of a chapter, part, or book: the text, its colour, and the occurrence number highlight_set and highlight_remove take.",
        "tags": [
          "highlight"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HighlightListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene, chapter, part, or book id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "highlight"
      },
      "post": {
        "operationId": "highlight_set",
        "summary": "Highlight a passage",
        "description": "Run a highlight over a quoted passage of a scene in one of the marker colours, or change the colour of an existing one. The words are never changed; only the formatting is. Read the scene first so the quote matches.",
        "tags": [
          "highlight"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HighlightSetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "highlight",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HighlightSetRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/manuscript/{docId}/highlights/remove": {
      "post": {
        "operationId": "highlight_remove",
        "summary": "Remove a highlight",
        "description": "Clear the highlight from a quoted passage of a scene. Quote the highlighted text as highlight_list shows it; the words are never changed.",
        "tags": [
          "highlight"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HighlightRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "highlight",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HighlightRemoveRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plots": {
      "get": {
        "operationId": "plot_list_grids",
        "summary": "List plot grids",
        "description": "List the plot grids in a project with their ids, the book each is linked to, and how many plot lines each has. Call plot_get_grid with an id to read one.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotListGridsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view_plots",
        "x-dabble-entitlement": "plotting"
      },
      "post": {
        "operationId": "plot_create_grid",
        "summary": "Create a plot grid",
        "description": "Add a new, empty plot grid to the project. Add plot lines with plot_create_line, then points; link it to a book with plot_link_book so its rows follow the scenes.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotCreateGridResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotCreateGridRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plots/{plotId}": {
      "get": {
        "operationId": "plot_get_grid",
        "summary": "Read a plot grid",
        "description": "Read a plot grid: its plot lines and every plot point by row, with the scene each row is aligned to when the grid is linked to a book. Use it to see the story's structure, find gaps, or locate plot point ids. Grid ids come from dabble_get_outline or plot_list_grids.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotGetGridResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from dabble_get_outline or plot_list_grids.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view_plots",
        "x-dabble-entitlement": "plotting"
      },
      "delete": {
        "operationId": "plot_remove_grid",
        "summary": "Remove a plot grid",
        "description": "Move a whole plot grid, with its lines and points, to the trash. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotRemoveGridResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/plots/{plotId}/lines": {
      "post": {
        "operationId": "plot_create_line",
        "summary": "Create a plot line",
        "description": "Add a plot line (a column) to a plot grid, e.g. \"Romance subplot\" or \"Mystery clues\". Returns the new line id for plot_create_point.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotCreateLineResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotCreateLineRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plots/{plotId}/points": {
      "post": {
        "operationId": "plot_create_point",
        "summary": "Create a plot point",
        "description": "Add a plot point (a card) to a plot line at a row of the grid. On a grid linked to a book, pass sceneId to put it on that scene's row; otherwise pass row (from plot_get_grid) or omit both to use the next empty row. The row must be empty for that line.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotCreatePointResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotCreatePointRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plot-points/{pointId}": {
      "patch": {
        "operationId": "plot_update_point",
        "summary": "Update a plot point",
        "description": "Change the title and/or text of an existing plot point. The text replaces the card body.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotUpdatePointResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pointId",
            "in": "path",
            "required": true,
            "description": "Plot point id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotUpdatePointRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "plot_remove_point",
        "summary": "Remove a plot point",
        "description": "Move a plot point to the trash. Its cell stays reserved so restoring it from the trash in Dabble puts it back on the same row. Confirm with the author first.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotRemovePointResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pointId",
            "in": "path",
            "required": true,
            "description": "Plot point id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/plot-points/{pointId}/move": {
      "post": {
        "operationId": "plot_move_point",
        "summary": "Move a plot point",
        "description": "Move a plot point to another row of its line, or onto another line (at the same row unless row or sceneId says otherwise). On a grid linked to a book, sceneId puts it on that scene's row. A row already holding a point is refused unless swap is true, which exchanges the two.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotMovePointResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pointId",
            "in": "path",
            "required": true,
            "description": "Plot point id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotMovePointRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plots/{plotId}/lines/{lineId}": {
      "patch": {
        "operationId": "plot_update_line",
        "summary": "Rename a plot line",
        "description": "Rename a plot line (a column) of a plot grid.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotUpdateLineResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lineId",
            "in": "path",
            "required": true,
            "description": "Plot line id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotUpdateLineRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "plot_remove_line",
        "summary": "Remove a plot line",
        "description": "Move a plot line and every plot point on it to the trash and take its column out of the grid. Confirm with the author first; Dabble can restore them from the trash.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotRemoveLineResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lineId",
            "in": "path",
            "required": true,
            "description": "Plot line id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/plots/{plotId}/lines/{lineId}/move": {
      "post": {
        "operationId": "plot_move_line",
        "summary": "Reorder plot lines",
        "description": "Move a plot line (a column) to a new position in its grid, 1 being the first line. The other lines keep their relative order.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotMoveLineResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lineId",
            "in": "path",
            "required": true,
            "description": "Plot line id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotMoveLineRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/plots/{plotId}/book": {
      "put": {
        "operationId": "plot_link_book",
        "summary": "Link a plot grid to a book",
        "description": "Link a plot grid to a book so each grid row follows one of the book's scenes, in order. Existing plot points keep their rows. A grid already linked to another book is moved to this one.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotLinkBookResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlotLinkBookRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "plot_unlink_book",
        "summary": "Unlink a plot grid from its book",
        "description": "Unlink a plot grid from its book. The scene column goes; plot lines and points stay where they are, on numbered rows.",
        "tags": [
          "plots"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlotUnlinkBookResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "plotId",
            "in": "path",
            "required": true,
            "description": "Plot grid id from plot_get_grid.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "plotting"
      }
    },
    "/projects/{projectId}/timelines": {
      "get": {
        "operationId": "timeline_list",
        "summary": "List timelines",
        "description": "List the project's timelines: each one's calendar, the book it is for (if any), its tracks and how many events it has and over what dates. Also lists the project's own calendars, for timeline_create, with where each is lined up against another: timeline_get_calendar reads one whole, and timeline_update_calendar changes it. Use timeline_get for the events.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "timeline"
      },
      "post": {
        "operationId": "timeline_create",
        "summary": "Create a timeline",
        "description": "Add a timeline, with a first track for its events. It reads its dates in a calendar: Gregorian (the default), days counted from a Day 0, or one of the project’s calendars from timeline_list. Link it to a book when it is that book’s; leave it unlinked for a world’s or a series’ history. Check timeline_list first to avoid duplicates.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/timelines/{timelineId}": {
      "get": {
        "operationId": "timeline_get",
        "summary": "Read a timeline",
        "description": "Read a timeline: its tracks, and its events in the order they happen (undated ones last), each with its dates, track, characters, place, scenes, weather and the start of its notes. Narrow it to one track, character or place. Use timeline_get_event for an event in full.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timelineId",
            "in": "path",
            "required": true,
            "description": "Timeline id from timeline_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "trackId",
            "in": "query",
            "required": false,
            "description": "Only the events on this track.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "query",
            "required": false,
            "description": "Only the events this character is in.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "query",
            "required": false,
            "description": "Only the events at this place, or a place inside it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Skip this many events (for paging).",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "At most this many events. Default 200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "timeline"
      },
      "patch": {
        "operationId": "timeline_update",
        "summary": "Edit a timeline",
        "description": "Rename a timeline, or link it to a book (null takes it off its book). Its calendar is changed in Dabble, where its dates can be checked against the new one.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timelineId",
            "in": "path",
            "required": true,
            "description": "Timeline id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "timeline_remove",
        "summary": "Remove a timeline",
        "description": "Move a whole timeline, with its tracks and events, to the trash. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timelineId",
            "in": "path",
            "required": true,
            "description": "Timeline id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/timeline-events/{eventId}": {
      "get": {
        "operationId": "timeline_get_event",
        "summary": "Read a timeline event",
        "description": "Read one timeline event in full: its dates in its calendar, track, characters, place, the scenes it happens in, weather and where it changes, who is born, dies or goes missing at it (with family trees), and its notes as Markdown.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineGetEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "Event id from timeline_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "timeline"
      },
      "patch": {
        "operationId": "timeline_update_event",
        "summary": "Edit a timeline event",
        "description": "Change a timeline event: its title, dates, track, characters, scenes, place, weather (and where it changes), notes, or who is born, dies or goes missing at it, or gains or loses a companion there (statusChanges, with family trees). Each field given replaces what is there; null clears it. A date set here is the event’s own, so it no longer follows another event. An event other events are counted from is re-dated in Dabble, where they move with it.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineUpdateEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "Event id from timeline_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineUpdateEventRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "timeline_remove_event",
        "summary": "Remove a timeline event",
        "description": "Move a timeline event to the trash. Events counted from its date keep their dates and follow nothing. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineRemoveEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "Event id from timeline_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/timelines/{timelineId}/tracks": {
      "post": {
        "operationId": "timeline_create_track",
        "summary": "Add a timeline track",
        "description": "Add a track (a named, coloured lane, like a plot line) to a timeline, after its other tracks. The time a track keeps (a time zone, another calendar, a place’s) is set in Dabble.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineCreateTrackResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timelineId",
            "in": "path",
            "required": true,
            "description": "Timeline id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineCreateTrackRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/timeline-tracks/{trackId}": {
      "patch": {
        "operationId": "timeline_update_track",
        "summary": "Edit a timeline track",
        "description": "Rename a timeline track or change its colour.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineUpdateTrackResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "trackId",
            "in": "path",
            "required": true,
            "description": "Track id from timeline_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineUpdateTrackRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "timeline_remove_track",
        "summary": "Remove a timeline track",
        "description": "Move a track to the trash. Its events stay on the timeline, under No Track, until it is restored or they are moved to another track (timeline_update_event). A timeline keeps at least one track. Confirm with the author first.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineRemoveTrackResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "trackId",
            "in": "path",
            "required": true,
            "description": "Track id from timeline_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/timelines/{timelineId}/events": {
      "post": {
        "operationId": "timeline_create_event",
        "summary": "Add a timeline event",
        "description": "Add an event to a timeline: what happens, when (in the calendar of the track it goes on), who is in it, where, the scenes it happens in, its weather (changing as it runs if it lasts), and who is born, dies or goes missing at it, or gains or loses a companion there (statusChanges, with family trees). As in Dabble, a day with no time is that day, and a start with no end is a moment. Omit when for an undated event. Read the timeline first so dates and tracks match.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineCreateEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timelineId",
            "in": "path",
            "required": true,
            "description": "Timeline id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineCreateEventRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/life": {
      "put": {
        "operationId": "timeline_set_character_life",
        "summary": "Set when and where a character was born and died",
        "description": "Set (or, with null, clear) when and where a character was born and died, which their lifeline on the timeline is drawn from and their age at each event read from. A life is written in one calendar, kept with it: one chosen for them — a track's (trackId: Orin, from Earth, is Gregorian on a Velara timeline), a calendar (calendarId), or a timeline's own (timelineId, for a life that keeps none yet) — or, set before either date, their birthplace's, where it keeps one (bornAtId). Leave them all out to keep the calendar their life is in already; a life that keeps none has its first date read in its birthplace's time (Gregorian where no place sets one), and a birthplace may be set before any date; a birthplace set once there is a date leaves it as it is. Give the dates in that calendar (its words or its parts); every timeline reads them on its own time, through a track that keeps the calendar or the project's line-up of calendars, and counts their age in its years. A change of calendar carries a date not given again across, where the two line up. timeline_get with characterId reads them back, as each track reads them.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineSetCharacterLifeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineSetCharacterLifeRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/places/{placeId}/calendar": {
      "put": {
        "operationId": "timeline_set_place_calendar",
        "summary": "Set the calendar a place keeps",
        "description": "Set the calendar a place keeps, which the places in it keep too unless they set their own: \"gregorian\", a calendar id from timeline_list, or null for the calendar of the place it is in (Gregorian at the top). Events set at a place are written in its calendar, and a character born there has their life written in it when the birthplace is set before either date (timeline_set_character_life with bornAtId). It resets the place's time zone to that calendar's own time, as Dabble does. Refused where dated events are set at the place or a place in it: change it in Dabble, where the writer chooses how their dates move.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineSetPlaceCalendarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "path",
            "required": true,
            "description": "Place id from location_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineSetPlaceCalendarRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/calendars": {
      "post": {
        "operationId": "timeline_create_calendar",
        "summary": "Create a calendar",
        "description": "Add one of the project's own calendars, for a world that does not count time as we do: its months (each with a name and days), its eras (each with a name, an abbreviation like \"TA\", and whether its years count forward or backward), its weekday names (none for no week), and, where it has them, a leap rule, a date format and a clock. Line it up with the Gregorian or another of the project's by naming one day in both, so timelines on the two can show each other's events and lives carry across. Timelines (timeline_create), tracks, places (timeline_set_place_calendar) and characters' lives (timeline_set_character_life) can keep it from then on. A leap year can add days to a month, months of its own (a leap period: three months every 15 years), or both; leap months are numbered after the calendar's own months, wherever they stand. Read it back with timeline_get_calendar; rename it, line it up again or change its months, eras and rules with timeline_update_calendar. Check timeline_list first to avoid duplicates.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineCreateCalendarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineCreateCalendarRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/calendars/{calendarId}": {
      "get": {
        "operationId": "timeline_get_calendar",
        "summary": "Read a calendar",
        "description": "Read one of the project's own calendars whole: its months (number, name, abbreviation, days), its leap rule (every, from, except, unless, the month that gains days and how many) and leap months with where each falls, how long a common and a leap year are and the order of their months, its eras (by index, as a date's era part names them), weekdays, date format, clock and line-up, and which months and eras its dates are in. Months are numbered 1 up in the order of the year, and a leap year's own months after them, in the order the leap rule lists them (a 12-month year's three leap months are 13, 14 and 15), wherever they stand in the year: dates, leap.month and after all use these numbers. Give fromYear and toYear to ask which of those years are leap, and, for up to 100, how long each is: 162 and 162 for year 162. Changes nothing.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineGetCalendarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "calendarId",
            "in": "path",
            "required": true,
            "description": "Calendar id from timeline_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fromYear",
            "in": "query",
            "required": false,
            "description": "With toYear: the first year to read, as its era counts it.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "toYear",
            "in": "query",
            "required": false,
            "description": "The last year to read; at most 10,000 after fromYear.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "era",
            "in": "query",
            "required": false,
            "description": "The era those years count in, by index; default the present.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "timeline"
      },
      "patch": {
        "operationId": "timeline_update_calendar",
        "summary": "Change a calendar",
        "description": "Change one of the project's own calendars: its name; its line-up (one day in it named as the same day in the Gregorian or another of the project's calendars, as timeline_create_calendar takes one; null for none); or its structure, as timeline_create_calendar takes it: months, leap, eras, weekdays, format, hoursPerDay, minutesPerHour. Each part given replaces that part whole; one left out stays. Read it first with timeline_get_calendar. Months are numbered 1 up in the order of the year, and a leap year's own months after them, in the order the leap rule lists them (a 12-month year's three leap months are 13, 14 and 15), wherever they stand in the year: dates, leap.month and after all use these numbers. Give each month and era you keep the number (was) it has now, so the dates in it follow it however the list changes; one with no was is new. A line-up and a structure are changed in separate calls.\n\nWhat happens to dates already written in it is shiftDates. \"keep\" (the default, as Dabble does) leaves each date's words: with a new line-up, its timelines' events, its tracks and the lives written in it move against every other calendar, and lives in other calendars are aged again against them; with a new structure, each date keeps its day, month (followed by was) and year, so a date after a lengthened month falls later, and an edit that takes out a month or era with dates in it, or leaves a date that is no longer a day (a month made shorter than it), is refused, naming the dates. \"move\" keeps each date at its moment against the calendar it is lined up with (its own start, where there is none), so their words change: events, tracks' and books' days, other calendars lined up with it, and lives in it. Events in the trash, and lives kept in no calendar of their own, keep their words. Give dryRun: true to see which dates would change, and how, without changing anything. Confirm a move, or any structure change with dates in it, with the author first.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineUpdateCalendarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "calendarId",
            "in": "path",
            "required": true,
            "description": "Calendar id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineUpdateCalendarRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "timeline_remove_calendar",
        "summary": "Remove a calendar",
        "description": "Move one of the project's own calendars to the trash, as its Delete in Dabble does. Timelines, tracks and places that keep it read their dates as Gregorian until it is restored; the result names the timelines and tracks. Confirm with the author first.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineRemoveCalendarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "calendarId",
            "in": "path",
            "required": true,
            "description": "Calendar id from timeline_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "timeline",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/calendars/convert": {
      "post": {
        "operationId": "timeline_convert_date",
        "summary": "Convert a date between calendars",
        "description": "Read a date in one calendar as the same day in another, by the project's calendar line-ups (directly, or through the calendars between): Velara to Gregorian, say. Changes nothing: use it to check a line-up, or a character's age, before changing either.",
        "tags": [
          "timeline"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimelineConvertDateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "timeline",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TimelineConvertDateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters": {
      "get": {
        "operationId": "character_list",
        "summary": "List characters",
        "description": "List every character in the project by cast, with ids, a one-line summary from each sheet, and whether each has a portrait. Use character_get for the full sheet.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "characters"
      },
      "post": {
        "operationId": "character_create",
        "summary": "Create a character",
        "description": "Add a character with a sheet of sections and term/value pairs (e.g. Appearance: Eye colour → Grey), plus optional free-form notes: straight under the Characters section (the default), or in a cast or another group that holds characters. To keep the sheet in the author's structure, build it from their character templates (templateIds, from character_list_templates) and fill in their terms. Check character_list first to avoid duplicates.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}": {
      "get": {
        "operationId": "character_get",
        "summary": "Read a character",
        "description": "Read one character's full sheet: its sections and term/value pairs, the free-form text before and after it, its note cards, the pages kept under it (read those with notebook_read_page), and its portrait and banner image when it has them. Ask for markdown to get the body as the author wrote it.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list or dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "sheet (default) is compact term: value lines; markdown is the full body.",
            "schema": {
              "type": "string",
              "enum": [
                "sheet",
                "markdown"
              ]
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "characters"
      },
      "patch": {
        "operationId": "character_update",
        "summary": "Edit a character",
        "description": "Change a character: rename it, set its subtitle or card excerpt, rewrite or append to the free-form text after its sheet, rewrite or remove the text before it (intro), swap one quoted passage of the body (a sheet value included) for new text, or remove whole sections by heading (removeSections). A replace may quote across paragraphs, bullets and headings as character_get format markdown shows them, and a block it leaves empty is removed. Use character_set_terms for term/value pairs. Read the character first so a quote matches. Pass only one of notes or intro, replace, or removeSections. A removal returns what went and saves a named version.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "character_remove",
        "summary": "Remove a character",
        "description": "Move a character, with the pages kept under them, to the trash, as Delete does in Dabble. Their scenes, family ties and timeline events keep them for when they are restored. Confirm with the author first; Dabble can restore them from the trash.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/scenes/{sceneId}/characters": {
      "get": {
        "operationId": "character_get_scene_cast",
        "summary": "Read a scene's characters",
        "description": "Read who a scene is written from (its point of view) and the characters the author added to it by hand, as its Planning tab shows them. Characters its text names are in it too; read the scene for those.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterGetSceneCastResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sceneId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "characters"
      }
    },
    "/projects/{projectId}/scenes/{sceneId}/pov": {
      "put": {
        "operationId": "character_set_pov",
        "summary": "Set a scene's point of view",
        "description": "Set the one character a scene is written from, replacing the one it has; null clears it. The plot grid shows it in its Point of View column.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterSetPovResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sceneId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterSetPovRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/scenes/{sceneId}/characters/{characterId}": {
      "put": {
        "operationId": "character_add_to_scene",
        "summary": "Add a character to a scene",
        "description": "Add a character to a scene by hand (its Planning tab's characters), for one the scene's text does not name. Nothing when they are added already.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterAddToSceneResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sceneId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters"
      },
      "delete": {
        "operationId": "character_remove_from_scene",
        "summary": "Take a character off a scene",
        "description": "Take back a character added to a scene by hand. One the scene names in its text stays in it: change the text in Dabble for that.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterRemoveFromSceneResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sceneId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_get_scene_cast.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/characters/{characterId}/terms": {
      "patch": {
        "operationId": "character_set_terms",
        "summary": "Set character sheet terms",
        "description": "Set or add term/value pairs on a character sheet. An existing term (matched by name, optionally within a heading) gets its value replaced; a new term is added at the end of its heading, creating the heading if needed. Everything else on the sheet is left as the author wrote it.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterSetTermsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterSetTermsRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/character-templates": {
      "get": {
        "operationId": "character_list_templates",
        "summary": "List character templates",
        "description": "List the character templates Dabble offers for a sheet (Demographics, Physical Appearance, ...): each one's id, the heading it adds and its terms in order, as the template picker inserts them. Use them with character_create (templateIds) or character_apply_template so a sheet keeps the author's structure instead of made-up headings.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterListTemplatesResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "The language the author writes their sheets in, as a code (en, de, fr, es, ...). Default en. Dabble translates a template into the author's language when they insert it, so match the language of their existing sheets.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "ca",
                "cs",
                "da",
                "de",
                "el",
                "es",
                "fi",
                "fr",
                "hr",
                "it",
                "lb",
                "nb",
                "nl",
                "nn",
                "pl",
                "pt",
                "ro",
                "sr",
                "sv",
                "uk"
              ]
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "characters"
      }
    },
    "/projects/{projectId}/character-templates/{templateId}": {
      "get": {
        "operationId": "character_get_template",
        "summary": "Read a character template",
        "description": "Read one character template: the heading it adds and its terms in order.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterGetTemplateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "templateId",
            "in": "path",
            "required": true,
            "description": "Template id from character_list_templates, or its name.",
            "schema": {
              "type": "string",
              "minLength": 1
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "The language the author writes their sheets in, as a code (en, de, fr, es, ...). Default en. Dabble translates a template into the author's language when they insert it, so match the language of their existing sheets.",
            "schema": {
              "type": "string",
              "enum": [
                "en",
                "ca",
                "cs",
                "da",
                "de",
                "el",
                "es",
                "fi",
                "fr",
                "hr",
                "it",
                "lb",
                "nb",
                "nl",
                "nn",
                "pl",
                "pt",
                "ro",
                "sr",
                "sv",
                "uk"
              ]
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "characters"
      }
    },
    "/projects/{projectId}/characters/{characterId}/templates": {
      "post": {
        "operationId": "character_apply_template",
        "summary": "Apply a template to a character",
        "description": "Put a character template on a character's sheet, as the template picker does: its heading and its terms, in the template's order. mode merge (the default) adds what is missing and puts the template's terms in its order under its heading, values kept, with the heading's other terms after them; missing only adds what is missing and moves nothing; replace rebuilds the sheet as the template, carrying matching values across and moving every other term under a \"Not in Template\" heading, nothing deleted (a heading whose terms move comes off, and the receipt names it; a heading with only text under it stays where it is). A term matches by heading and name, ignoring case and spacing; a term under no heading matches the template's term of that name when only one template has it. Text under a heading stays with it: merge and missing leave the text after the sheet alone, and replace moves it with the last heading when that heading moves. A row holding a suggestion, or anything Connect could not write again, is refused rather than moved; missing moves nothing. Saves a named version, so the author can go back.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterApplyTemplateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterApplyTemplateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/casts": {
      "post": {
        "operationId": "character_create_cast",
        "summary": "Add a cast",
        "description": "Add an empty cast (a group of characters, such as \"Main Characters\" or \"The Crew\") at the end of the Characters section. Then add characters to it with character_create, or move them in with dabble_move_doc. Check character_list first to avoid duplicates.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterCreateCastResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CharacterCreateCastRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/casts/{castId}": {
      "delete": {
        "operationId": "character_remove_cast",
        "summary": "Remove a cast",
        "description": "Move a cast to the trash with every character, family tree, hierarchy and page in it, as Delete does in Dabble. Move characters out first (dabble_move_doc) to keep them. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "characters"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CharacterRemoveCastResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "castId",
            "in": "path",
            "required": true,
            "description": "Cast id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "characters",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/characters/{characterId}/family": {
      "get": {
        "operationId": "family_get",
        "summary": "Read a character's family",
        "description": "Read a character's family as of a moment of the story: their parents, partners, children, siblings and grandparents, their companions and who they are a companion of, how each tie stands then (in force, over, still to come), who is alive, dead, missing or not yet born, when they are born and die, the family trees they are on, and the moments their family changes. Defaults to the latest point of the story.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOf",
            "in": "query",
            "required": false,
            "description": "Read it as of a moment of the story: \"before\", \"scene:<sceneId>\" or \"event:<eventId>\". Default: \"latest\", everything that ever happens.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "family_trees"
      }
    },
    "/projects/{projectId}/characters/{characterId}/parents/{parentId}": {
      "put": {
        "operationId": "family_set_parent",
        "summary": "Set a parent",
        "description": "Make one character a parent of another, or change how: a birth, adoptive, step or foster parent, or a guardian, and when it began and ended (a death ends nothing here: it is worked out from family_set_life). Siblings follow from shared parents by themselves. Fields left out keep what is there; null clears a moment. A family never loops: a child's ancestor cannot become their child.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilySetParentResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "The child, from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "parentId",
            "in": "path",
            "required": true,
            "description": "The parent, from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilySetParentRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/partners/{partnerId}": {
      "put": {
        "operationId": "family_set_partner",
        "summary": "Set partners",
        "description": "Make two characters partners, or change how: married, partners or betrothed, when they got together, and when and why it ended (divorced, separated). A death ends it by itself, worked out from family_set_life; give an end only for one that is not a death. Fields left out keep what is there; null clears.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilySetPartnerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "partnerId",
            "in": "path",
            "required": true,
            "description": "The other partner, from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilySetPartnerRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/siblings/{siblingId}": {
      "put": {
        "operationId": "family_set_sibling",
        "summary": "Set siblings",
        "description": "Say two characters are siblings outright, for when their parents are not in the project (or half-siblings). Siblings who share a parent need none: set their parents with family_set_parent.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilySetSiblingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "siblingId",
            "in": "path",
            "required": true,
            "description": "The other sibling, from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilySetSiblingRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/companions/{companionId}": {
      "put": {
        "operationId": "family_set_companion",
        "summary": "Set a companion",
        "description": "Make one character another's companion, or change how: a bond outside the bloodline (an AI, a familiar, a bonded animal, a ship's mind). Kept one way: the character has the companion. A character can have several, a companion can serve several, and a companion can have companions of its own; never itself. It is never kinship: it makes no parents, siblings or partners, and no death ends it (an AI can outlive its owner), so end it with until where the story does. descriptor is what the companion is to them, shown on the tree's line (up to 40 characters: \"Link AI\", \"familiar\"); family_get lists the descriptors already used. Fields left out keep what is there; null clears. replaceExisting: true takes away a partner or sibling tie between the two in the same change (and the companion from parents they share), for a companion that was kept as a partner or sibling before.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilySetCompanionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Whose companion it is, from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "companionId",
            "in": "path",
            "required": true,
            "description": "The companion, from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilySetCompanionRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/family/{relativeId}": {
      "delete": {
        "operationId": "family_unlink",
        "summary": "Remove a family tie",
        "description": "Take away a tie between two characters: the relative as the character’s parent, child, partner, sibling (said outright) or companion, or the character the relative is a companion of (companionOf), or with no rel every tie between them. To end a tie in the story instead, set when it ended. Siblings who share a parent are tied through that parent. Confirm with the author first.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyUnlinkResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "relativeId",
            "in": "path",
            "required": true,
            "description": "The relative, from family_get.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rel",
            "in": "query",
            "required": false,
            "description": "What the relative is to the character. Omit for every tie between them.",
            "schema": {
              "type": "string",
              "enum": [
                "parent",
                "child",
                "partner",
                "sibling",
                "companion",
                "companionOf"
              ]
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/characters/{characterId}/family-life": {
      "put": {
        "operationId": "family_set_life",
        "summary": "Set when a character is born, dies or goes missing",
        "description": "Set (or, with null, clear) the moments of the story a character is born, dies or goes missing at. A death ends their partnerships and the posts they hold by itself, and widows their partners. This is where in the story it happens; when on the calendar is timeline_set_character_life. A moment at a timeline event (\"event:<id>\") is that event's status change, as Change Status… sets it in Dabble: timeline_get_event lists it, and a death there also sets their Died date to the event's day (cleared again, where it is that day, when the death moves off the event). To set several at one event, timeline_update_event takes statusChanges. An event in no scene is placed in the story by its date. Default: alive from before the story, for good.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilySetLifeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilySetLifeRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/family-trees": {
      "get": {
        "operationId": "family_tree_list",
        "summary": "List family trees",
        "description": "List the family tree pages: each one’s name, the character it grows from, how far it reaches and how many it shows. Use family_tree_get for who is on one.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyTreeListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "family_trees"
      },
      "post": {
        "operationId": "family_tree_create",
        "summary": "Create a family tree",
        "description": "Add a family tree page, growing from one character: it shows their connected family (through parents, children, siblings and partners) by itself, as ties are set. Check family_tree_list first to avoid duplicates.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyTreeCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilyTreeCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/family-trees/{treeId}": {
      "get": {
        "operationId": "family_tree_get",
        "summary": "Read a family tree",
        "description": "Read a family tree as of a moment of the story: everyone on it and how they stand then (alive, dead, missing, not yet born), the parent and partner ties among them and how each stands, siblings said outright, the companion ties (and whether the tree shows companions at all), the companions placed on it by themselves, who is folded away, and the moments the family changes. Defaults to the latest point.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyTreeGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "treeId",
            "in": "path",
            "required": true,
            "description": "Family tree id from family_tree_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOf",
            "in": "query",
            "required": false,
            "description": "Read it as of a moment of the story: \"before\", \"scene:<sceneId>\" or \"event:<eventId>\". Default: \"latest\", everything that ever happens.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "family_trees"
      },
      "patch": {
        "operationId": "family_tree_update",
        "summary": "Edit a family tree",
        "description": "Change a family tree page: rename it, grow it from another character, set how far it reaches (null: all of the family), fold characters away from it or bring them back, show (open) or hide (close) the own family of a partner who married in, show or hide every companion on it (showCompanions: false for a pure bloodline view; the ties stay), or place a companion on it by itself (a card of its own, whether or not its characters are on the tree) or take one off.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyTreeUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "treeId",
            "in": "path",
            "required": true,
            "description": "Family tree id from family_tree_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FamilyTreeUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "family_tree_remove",
        "summary": "Remove a family tree",
        "description": "Move a family tree page to the trash. The family itself stays: its ties are the characters’, and show on every tree. Characters filed in the tree go to the trash with it, as in Dabble; move them out first (dabble_move_doc) to keep them. Confirm with the author first.",
        "tags": [
          "family-trees"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FamilyTreeRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "treeId",
            "in": "path",
            "required": true,
            "description": "Family tree id from family_tree_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "family_trees",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/hierarchies": {
      "get": {
        "operationId": "hierarchy_list",
        "summary": "List hierarchies",
        "description": "List the role hierarchies (a navy, a royal court, a company, a guild): each one’s roles, posts and vacancies at the latest point of the story. Use hierarchy_get for who holds what.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "hierarchies"
      },
      "post": {
        "operationId": "hierarchy_create",
        "summary": "Create a hierarchy",
        "description": "Add a role hierarchy: ranks and posts that change over the story, and who holds them (a navy, a royal court, a company, a guild). Give its roles highest first, or start from a preset’s (army: General to Private; navy: Admiral to Midshipman; court: Monarch to Page; company: Chief to Associate; guild: Grandmaster to Apprentice). Add posts with hierarchy_add_post. Check hierarchy_list first to avoid duplicates.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}": {
      "get": {
        "operationId": "hierarchy_get",
        "summary": "Read a hierarchy",
        "description": "Read a hierarchy as of a moment of the story: its roles highest first, the posts at each, who holds each then (or that it is vacant, and since when), who reports to whom, every holding with when it began and ended and why, and the moments it changes. Defaults to the latest point.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOf",
            "in": "query",
            "required": false,
            "description": "Read it as of a moment of the story: \"before\", \"scene:<sceneId>\" or \"event:<eventId>\". Default: \"latest\", everything that ever happens.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "hierarchies"
      },
      "patch": {
        "operationId": "hierarchy_update",
        "summary": "Rename a hierarchy",
        "description": "Rename a hierarchy.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "hierarchy_remove",
        "summary": "Remove a hierarchy",
        "description": "Move a hierarchy, with its roles, posts and who held them, to the trash. Characters filed in it go with it, as in Dabble; move them out first (dabble_move_doc) to keep them. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/characters/{characterId}/ranks": {
      "get": {
        "operationId": "hierarchy_get_character",
        "summary": "Read a character's ranks",
        "description": "Read where a character stands in every hierarchy as of a moment of the story: the post they hold then, their role, who they report to and who reports to them, and every post they have held, will hold or held before.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyGetCharacterResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "asOf",
            "in": "query",
            "required": false,
            "description": "Read it as of a moment of the story: \"before\", \"scene:<sceneId>\" or \"event:<eventId>\". Default: \"latest\", everything that ever happens.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "hierarchies"
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/roles": {
      "post": {
        "operationId": "hierarchy_add_role",
        "summary": "Add a role to a hierarchy",
        "description": "Add a role (a rank: Captain, Duke) to a hierarchy, below the others or above another.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyAddRoleResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyAddRoleRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/roles/{roleId}": {
      "patch": {
        "operationId": "hierarchy_update_role",
        "summary": "Edit a role",
        "description": "Rename a role, change its note (null clears it), or move it above another role (null: to the bottom).",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyUpdateRoleResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "roleId",
            "in": "path",
            "required": true,
            "description": "Role id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyUpdateRoleRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "hierarchy_remove_role",
        "summary": "Remove a role",
        "description": "Take a role away from a hierarchy, with its posts and every holding of them: as if they never were. Posts that reported to those report up the line. Confirm with the author first.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyRemoveRoleResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "roleId",
            "in": "path",
            "required": true,
            "description": "Role id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/posts": {
      "post": {
        "operationId": "hierarchy_add_post",
        "summary": "Add a post to a hierarchy",
        "description": "Add a post at a role (\"Captain of the Merrow\"): the seat a character holds. It reports to the post above it in the chart, and a post no one holds is vacant. Give it a holder to fill it from when it is made, or appoint one later (hierarchy_appoint).",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyAddPostResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyAddPostRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/posts/{postId}": {
      "patch": {
        "operationId": "hierarchy_update_post",
        "summary": "Edit a post",
        "description": "Change a post: rename it, move it to another role, change who it reports to (null: to the top), when it is made or done away with (null clears), or the other posts it reports to as well (replacing the list). A line that would loop is refused.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyUpdatePostResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "postId",
            "in": "path",
            "required": true,
            "description": "Post id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyUpdatePostRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "hierarchy_remove_post",
        "summary": "Remove a post",
        "description": "Take a post away, with every holding of it: as if it never was (to end it in the story, set its until). Posts that reported to it report up its line. Confirm with the author first.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyRemovePostResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "postId",
            "in": "path",
            "required": true,
            "description": "Post id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/holdings": {
      "post": {
        "operationId": "hierarchy_appoint",
        "summary": "Appoint a character to a post",
        "description": "Have a character hold a post, from a moment (default: before the story) until another (default: until they die, or for good), and why it ended (left, removed; a death ends it by itself). For a promotion, demotion or transfer of someone already in a post, use hierarchy_move_holder.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyAppointResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyAppointRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/holdings/{holdingId}": {
      "patch": {
        "operationId": "hierarchy_update_holding",
        "summary": "Edit a holding",
        "description": "Change a holding: who holds it, which post, from when, until when (null: until they die, or for good) and why it ended. To move someone to another post at a moment, use hierarchy_move_holder.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyUpdateHoldingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "holdingId",
            "in": "path",
            "required": true,
            "description": "Holding id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyUpdateHoldingRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "hierarchy_remove_holding",
        "summary": "Remove a holding",
        "description": "Take a holding away, as if they never held the post (to have them leave it in the story, set its until). Confirm with the author first.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyRemoveHoldingResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "holdingId",
            "in": "path",
            "required": true,
            "description": "Holding id from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/hierarchies/{hierarchyId}/holdings/{holdingId}/move": {
      "post": {
        "operationId": "hierarchy_move_holder",
        "summary": "Promote, demote or transfer a holder",
        "description": "Move a holder to another post at a moment of the story: a promotion, a demotion or a transfer. Their holding ends there and a new one starts there, leaving the old post vacant; an ending it had later goes with the new one. They must hold the post at that moment.",
        "tags": [
          "hierarchies"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HierarchyMoveHolderResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hierarchyId",
            "in": "path",
            "required": true,
            "description": "Hierarchy id from hierarchy_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "holdingId",
            "in": "path",
            "required": true,
            "description": "The holding of the post they leave, from hierarchy_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "hierarchies",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HierarchyMoveHolderRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/places": {
      "get": {
        "operationId": "location_list",
        "summary": "List places",
        "description": "List every place in the project as a tree (a planet, the towns on it, the houses in them), with ids, how deep each sits, the place it is in, a one-line summary from its sheet, and whether it has a banner. Use location_get for a place in full.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "locations"
      },
      "post": {
        "operationId": "location_create",
        "summary": "Create a place",
        "description": "Add a place, straight under Locations or inside another place (a town on a planet, a room in a house), with a sheet of sections and term/value pairs and optional free-form text. Check location_list first to avoid duplicates.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationCreateRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/places/{placeId}": {
      "get": {
        "operationId": "location_get",
        "summary": "Read a place",
        "description": "Read one place in full: its sheet (sections of term/value pairs) and the text before and after it, the places it is in and the places in it, its note cards, the pages kept under it (its tabs; read them with notebook_read_page), the scenes set there, the characters who live there, the timeline events set there, and its banner. Ask for markdown to get the body as the author wrote it.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "path",
            "required": true,
            "description": "Place id from location_list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "sheet (default) is compact term: value lines; markdown is the full body.",
            "schema": {
              "type": "string",
              "enum": [
                "sheet",
                "markdown"
              ]
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "locations"
      },
      "patch": {
        "operationId": "location_update",
        "summary": "Edit a place",
        "description": "Change a place: rename it, set its subtitle or card excerpt, rewrite or append to the text after its sheet, rewrite or remove the text before it (intro), swap one quoted passage of its body (a sheet value included) for new text, or remove whole sections by heading (removeSections). A replace may quote across paragraphs, bullets and headings as location_get format markdown shows them, and a block it leaves empty is removed. Use location_set_terms for term/value pairs, and dabble_move_doc to move it into another place. Pass only one of notes or intro, replace, or removeSections. A removal returns what went and saves a named version.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "path",
            "required": true,
            "description": "Place id from location_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "location_remove",
        "summary": "Remove a place",
        "description": "Move a place, with the places in it and its pages, to the trash. Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "path",
            "required": true,
            "description": "Place id from location_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/places/{placeId}/terms": {
      "patch": {
        "operationId": "location_set_terms",
        "summary": "Set place sheet terms",
        "description": "Set or add term/value pairs on a place's sheet. An existing term (matched by name, optionally within a heading) gets its value replaced; a new term is added at the end of its heading, creating the heading if needed. Everything else on the sheet is left as the author wrote it.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationSetTermsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "placeId",
            "in": "path",
            "required": true,
            "description": "Place id from location_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationSetTermsRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/scenes/{sceneId}/place": {
      "put": {
        "operationId": "location_set_scene_place",
        "summary": "Set where a scene happens",
        "description": "Set the one place a scene is set at (its Location on the Planning tab), replacing the one it has; null clears it. location_get lists a place's scenes.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationSetScenePlaceResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sceneId",
            "in": "path",
            "required": true,
            "description": "Scene id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationSetScenePlaceRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/characters/{characterId}/home": {
      "put": {
        "operationId": "location_set_home",
        "summary": "Set where a character lives",
        "description": "Set the one place a character lives at (where they belong when nothing says otherwise), replacing the one they have; null clears it. location_get lists a place's residents.",
        "tags": [
          "locations"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LocationSetHomeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "description": "Character id from character_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "locations",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LocationSetHomeRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/notebook": {
      "get": {
        "operationId": "notebook_get_tree",
        "summary": "List notebook pages",
        "description": "List the notebook (headed by its id, \"notebook\"): folders and pages with ids and word counts, then any pages kept under casts, characters and places. Use notebook_read_page to read a page.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookGetTreeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notebook"
      }
    },
    "/projects/{projectId}/notebook/pages/{pageId}": {
      "get": {
        "operationId": "notebook_read_page",
        "summary": "Read a notebook page",
        "description": "Read a notebook page as Markdown (or plain text), paginated for long pages, wherever the page lives: the notebook, a folder, or under a character or cast. Also returns the note cards attached to it.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookReadPageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageId",
            "in": "path",
            "required": true,
            "description": "Page id from notebook_get_tree.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 500,
              "maximum": 60000
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notebook"
      },
      "patch": {
        "operationId": "notebook_update_page",
        "summary": "Edit a notebook page",
        "description": "Change a notebook page: rename it, replace its whole text, swap one quoted passage for new text while leaving the rest alone, or remove whole sections by heading (removeSections). A replace may quote across paragraphs, bullets and headings as notebook_read_page shows them in markdown, and a block it leaves empty is removed. Read the page first so the quote matches. Pass only one of text, replace, or removeSections; use notebook_append_page to add to the end. A removal returns what went and saves a named version.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookUpdatePageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageId",
            "in": "path",
            "required": true,
            "description": "Page id from notebook_get_tree or character_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotebookUpdatePageRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/notebook/pages": {
      "post": {
        "operationId": "notebook_create_page",
        "summary": "Create a notebook page",
        "description": "Add a page to the notebook (or inside a folder, a character or a place; pages do not nest, so use a folder to group them) with optional starting text in plain text or light Markdown. Good for research, world-building, timelines, and reference material. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookCreatePageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotebookCreatePageRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/notebook/folders": {
      "post": {
        "operationId": "notebook_create_folder",
        "summary": "Create a notebook folder",
        "description": "Add a folder to the notebook, optionally inside another folder or a cast.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookCreateFolderResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotebookCreateFolderRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/notebook/pages/{pageId}/append": {
      "post": {
        "operationId": "notebook_append_page",
        "summary": "Append to a notebook page",
        "description": "Add paragraphs to the end of a notebook page without touching what is already there. To change existing text use notebook_update_page.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookAppendPageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageId",
            "in": "path",
            "required": true,
            "description": "Page id from notebook_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotebookAppendPageRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/notebook/{docId}": {
      "delete": {
        "operationId": "notebook_remove",
        "summary": "Remove a notebook page or folder",
        "description": "Move a notebook page, image page or folder to the trash, with the pages and folders inside it, as Delete does in Dabble. Pages kept under a character or a place go the same way, and so does an image page wherever it is filed (among ideas too). Confirm with the author first; Dabble can restore it from the trash.",
        "tags": [
          "notebook"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotebookRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Page, image page or folder id from notebook_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/ideas": {
      "get": {
        "operationId": "ideas_get_tree",
        "summary": "List the Ideas notebook",
        "description": "List the author’s Ideas notebook: folders, ideas and image pages with ids, word counts and one-line descriptions. The Ideas notebook is its own project: find it in dabble_list_projects as the project of type \"ideas\" (section personal). Use ideas_read_idea to read one.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasGetTreeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notebook"
      },
      "post": {
        "operationId": "ideas_create_idea",
        "summary": "Create an idea",
        "description": "Add an idea to the Ideas notebook (or inside one of its folders) with optional starting text in plain text or light Markdown, a one-line description, and a banner colour. Good for capturing a premise, a scene that does not belong anywhere yet, or a stray thought. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasCreateIdeaResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdeasCreateIdeaRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/ideas/{ideaId}": {
      "get": {
        "operationId": "ideas_read_idea",
        "summary": "Read an idea",
        "description": "Read one idea from the Ideas notebook as Markdown (or plain text), paginated for long ideas, with its one-line description and banner colour.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasReadIdeaResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ideaId",
            "in": "path",
            "required": true,
            "description": "Idea id from ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 500,
              "maximum": 60000
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notebook"
      },
      "patch": {
        "operationId": "ideas_update_idea",
        "summary": "Edit an idea",
        "description": "Change an idea: rename it, set its one-line description or banner colour (none takes the colour off; an image banner set in Dabble stays), replace its whole text, or swap one quoted passage for new text while leaving the rest alone. A replace may quote across paragraphs, bullets and headings as the markdown read shows them, and a block it leaves empty is removed; a removal returns what went and saves a named version. Read the idea first so the quote matches. Pass text OR replace, not both; use ideas_append_idea to add to the end.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasUpdateIdeaResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ideaId",
            "in": "path",
            "required": true,
            "description": "Idea id from ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdeasUpdateIdeaRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "ideas_remove",
        "summary": "Remove an idea or folder",
        "description": "Move an idea, or a folder and everything in it, to the Ideas notebook’s trash, where the author can restore it in Dabble. Nothing is deleted outright. Confirm with the author first.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ideaId",
            "in": "path",
            "required": true,
            "description": "Idea or folder id from ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/ideas/folders": {
      "post": {
        "operationId": "ideas_create_folder",
        "summary": "Create an ideas folder",
        "description": "Add a folder to the Ideas notebook, optionally inside another folder.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasCreateFolderResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdeasCreateFolderRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/ideas/{ideaId}/append": {
      "post": {
        "operationId": "ideas_append_idea",
        "summary": "Append to an idea",
        "description": "Add paragraphs to the end of an idea without touching what is already there. To change existing text use ideas_update_idea.",
        "tags": [
          "ideas"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdeasAppendIdeaResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "The Ideas notebook’s project id: the project of type \"ideas\" in dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ideaId",
            "in": "path",
            "required": true,
            "description": "Idea id from ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notebook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdeasAppendIdeaRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/avatar": {
      "put": {
        "operationId": "images_set_avatar",
        "summary": "Set a character portrait",
        "description": "Set, replace or remove a character's portrait from an image link. Dabble shows it as a small circle beside the character's name and on its card. Generate or find the image yourself, then pass its public https link; Dabble crops it to a square and keeps its own copy. Left to itself it keeps the subject in view; pass focus (a point, such as the face) or crop (an exact region) to choose the framing, and call again with the same link and replace: true to adjust it. character_get says whether a character already has a portrait: one that is there is only replaced when you pass replace: true, so ask the author first.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesSetAvatarResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Id of the document, from character_list, notebook_get_tree or ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-destructive": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImagesSetAvatarRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/banner": {
      "put": {
        "operationId": "images_set_banner",
        "summary": "Set a banner image",
        "description": "Set, replace or remove the banner image across the top of a character, a notebook page, an idea or a place, or the image across the top of a timeline event's card. Generate or find the image yourself, then pass its public https link; Dabble crops it to a wide, short strip (about 4.5 times as wide as it is tall; three times for an event) and keeps its own copy, so a landscape image with no text in it works best. Left to itself it keeps the subject in view; pass focus (a point to keep in view, such as the skyline) or crop (an exact region) to choose the framing, and call again with the same link and replace: true to adjust it. A banner that is already there is only replaced when you pass replace: true, so ask the author first. A banner colour, where the document has one, is left as it is.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesSetBannerResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Id of the document, from character_list, notebook_get_tree or ideas_get_tree.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-destructive": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImagesSetBannerRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/image-pages": {
      "post": {
        "operationId": "images_create_page",
        "summary": "Add an image page",
        "description": "Add an image page: a page that shows one picture, whole, such as a map, a floor plan or a character's portrait sheet. It goes at the end of the notebook, or of the folder, character or place named by parentId. Generate or find the image yourself, then pass its public https link (or the url of one in the library, from images_list_assets); Dabble keeps its own copy, uncropped, and adds it to the author's library. Omit imageUrl for an empty page the author fills in Dabble.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesCreatePageResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImagesCreatePageRequest"
              }
            }
          }
        }
      }
    },
    "/assets": {
      "get": {
        "operationId": "images_list_assets",
        "summary": "List the image library",
        "description": "List the images in the author's library (the Assets page in the app): every picture they have uploaded, picked or had set through an app, kept whole. The library belongs to the author, not to one project, so an image added in one project can be used in another. Pass projectId to list only the images added in or cropped for that project, and search to match part of a name. To use one, pass its url as imageUrl to images_set_avatar or images_set_banner. Newest first.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesListAssetsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "required": false,
            "description": "Only images added in, or cropped for, this project.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Only images whose name contains this, whatever the case.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ]
      },
      "post": {
        "operationId": "images_add_asset",
        "summary": "Add an image to the library",
        "description": "Add an image to the author's library from a link, without putting it on any document. Generate or find the image yourself, then pass its public https link; Dabble fetches it once and keeps its own copy, whole and uncropped, where the author finds it on the Assets page and can use it for a portrait, a banner, a cover or in their text. Pass name to say what it is. projectId is the project it is being added for, and counts against that project's image budget. Adding an image that is already in the library returns the one that is there.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesAddAssetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "x-dabble-capability": "view",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImagesAddAssetRequest"
              }
            }
          }
        }
      }
    },
    "/assets/{assetId}": {
      "patch": {
        "operationId": "images_rename_asset",
        "summary": "Rename a library image",
        "description": "Change the name of an image in the author's library. The name is only its label there: the stored file, and every document showing the image, are unchanged.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesRenameAssetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "parameters": [
          {
            "name": "assetId",
            "in": "path",
            "required": true,
            "description": "Id of the image, from images_list_assets.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImagesRenameAssetRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "images_remove_asset",
        "summary": "Remove a library image",
        "description": "Take an image, and the crops cut from it, out of the author's library. It no longer shows on the Assets page or in the image picker. Documents already showing it keep it: to take a portrait or a banner off a document, call images_set_avatar or images_set_banner with imageUrl null. The author chose what is in their library, so ask them before removing anything.",
        "tags": [
          "images"
        ],
        "security": [
          {
            "oauth2": [
              "images:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImagesRemoveAssetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "images:write",
        "parameters": [
          {
            "name": "assetId",
            "in": "path",
            "required": true,
            "description": "Id of the image, from images_list_assets.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/notes": {
      "get": {
        "operationId": "notes_list",
        "summary": "List docs with note cards",
        "description": "List every doc in the project that carries note cards, with how many each has. Call notes_get with a doc id to read them.",
        "tags": [
          "notes"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotesListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notes"
      }
    },
    "/projects/{projectId}/docs/{docId}/notes": {
      "get": {
        "operationId": "notes_get",
        "summary": "Read note cards",
        "description": "Read the note cards attached to a scene, chapter, character, page, or plot point: title, text, and label. Use notes_list to find the docs that have any.",
        "tags": [
          "notes"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotesGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id from dabble_get_outline or notes_list.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "notes"
      },
      "post": {
        "operationId": "notes_add",
        "summary": "Add a note card",
        "description": "Attach a new note card to a scene, chapter, character, plot point, or notebook page. Plain text or light Markdown (headings, bullets, bold). Good for research, continuity checks, reminders, and ideas. The card shows in the Notes sidebar marked as written by this app; it never touches the manuscript.",
        "tags": [
          "notes"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotesAddResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notes",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotesAddRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/notes/{noteId}": {
      "patch": {
        "operationId": "notes_update",
        "summary": "Update a note card",
        "description": "Change the text or title of a note card, or add a label to it (a card can wear several). By default the text replaces the card body; set append to add to the end instead. Any note can be edited, not only ones this app wrote.",
        "tags": [
          "notes"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotesUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id the note belongs to.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "noteId",
            "in": "path",
            "required": true,
            "description": "Note id from notes_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notes",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotesUpdateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "notes_remove",
        "summary": "Remove a note card",
        "description": "Delete a note card from a scene, chapter, character, plot point, or notebook page. Confirm with the author first: unlike a document, a removed note card does not go to the trash.",
        "tags": [
          "notes"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotesRemoveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id the note belongs to.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "noteId",
            "in": "path",
            "required": true,
            "description": "Note id from notes_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "notes",
        "x-dabble-destructive": true
      }
    },
    "/projects/{projectId}/comments": {
      "get": {
        "operationId": "comments_get",
        "summary": "Read comments",
        "description": "Read comment threads and pending tracked changes on a scene (or across the whole project), each with the passage it is anchored to, its author, and replies. Open threads only unless includeResolved is set.",
        "tags": [
          "comments"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentsGetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "query",
            "required": false,
            "description": "Scene or doc id. Omit to read every open thread in the project.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeResolved",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "comments"
      }
    },
    "/projects/{projectId}/docs/{docId}/comments": {
      "post": {
        "operationId": "comments_add",
        "summary": "Comment on a passage",
        "description": "Leave a comment anchored to a passage of manuscript text, exactly like a collaborator would in the margin. The passage is highlighted and the thread appears in the Comments sidebar under this app's name. Quote the passage as manuscript_read returns it; a distinctive sentence or phrase is enough. To comment on a doc's title (or a book's subtitle or author line) instead of its text, pass field and quote the title. The manuscript text itself is never changed.",
        "tags": [
          "comments"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentsAddResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene (or other text doc) id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "comment",
        "x-dabble-entitlement": "comments",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentsAddRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/comments/{commentId}/replies": {
      "post": {
        "operationId": "comments_reply",
        "summary": "Reply to a comment",
        "description": "Add a reply to an existing comment thread, under this app's name.",
        "tags": [
          "comments"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentsReplyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id the thread belongs to.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "in": "path",
            "required": true,
            "description": "Thread id from comments_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "comment",
        "x-dabble-entitlement": "comments",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentsReplyRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/comments/{commentId}/resolve": {
      "post": {
        "operationId": "comments_resolve",
        "summary": "Resolve a comment",
        "description": "Mark a comment thread resolved. Only threads started by you or by this app can be resolved here; tracked changes are accepted or rejected in Dabble.",
        "tags": [
          "comments"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentsResolveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id the thread belongs to.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "in": "path",
            "required": true,
            "description": "Thread id from comments_get.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "comment",
        "x-dabble-entitlement": "comments"
      }
    },
    "/projects/{projectId}/changes": {
      "get": {
        "operationId": "changes_list",
        "summary": "List pending changes",
        "description": "List the tracked changes waiting for the author on a scene (or across the whole project): what each removes or adds, who suggested it, and the text around it. Changes Dabble Connect suggested are marked, since only those can be withdrawn with changes_withdraw; everything else is accepted or rejected in Dabble.",
        "tags": [
          "track-changes"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangesListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "query",
            "required": false,
            "description": "Scene or doc id. Omit to list every pending change in the project.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view",
        "x-dabble-entitlement": "track_changes"
      }
    },
    "/projects/{projectId}/docs/{docId}/changes": {
      "post": {
        "operationId": "changes_suggest",
        "summary": "Suggest an edit",
        "description": "Suggest an edit to manuscript text as a tracked change, exactly as an editor would with Track Changes on. The words are not changed: the suggestion shows in the scene and in the Comments sidebar under this app's name, and the author accepts or rejects it in Dabble. Quote the passage as manuscript_read returns it; a distinctive sentence or phrase is enough. To suggest an edit to a doc's title (or a book's subtitle or author line), pass field and quote the title. Replace it with text (empty text suggests deleting it), or put text before or after it. One paragraph at a time: neither the passage nor the text may cross a line break, and a passage already under a pending change cannot be suggested on.",
        "tags": [
          "track-changes"
        ],
        "security": [
          {
            "oauth2": [
              "manuscript:suggest"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangesSuggestResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "manuscript:suggest",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Scene (or other manuscript doc) id from dabble_get_outline.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "track_changes",
        "x-dabble-entitlement": "track_changes",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangesSuggestRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/docs/{docId}/changes/{changeId}/withdraw": {
      "post": {
        "operationId": "changes_withdraw",
        "summary": "Withdraw a suggestion",
        "description": "Take back a suggestion this app made, as rejecting it in Dabble would: suggested text is removed, a passage marked for deletion is restored, and the thread is closed. Only changes Dabble Connect suggested for you can be withdrawn; everything else is accepted or rejected in Dabble.",
        "tags": [
          "track-changes"
        ],
        "security": [
          {
            "oauth2": [
              "manuscript:suggest"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangesWithdrawResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "manuscript:suggest",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id the change is on.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "changeId",
            "in": "path",
            "required": true,
            "description": "Change id from changes_list or changes_suggest.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "track_changes",
        "x-dabble-entitlement": "track_changes"
      }
    },
    "/projects/{projectId}/goals": {
      "get": {
        "operationId": "goals_get_progress",
        "summary": "Read goals and writing history",
        "description": "Read the project's word-count goals and the words written per day over the last two months (the author's own words, then everyone's). Useful for pacing questions and progress summaries.",
        "tags": [
          "goals"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GoalsGetProgressResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "view_goals",
        "x-dabble-entitlement": "goals"
      },
      "post": {
        "operationId": "goals_set",
        "summary": "Set a word-count goal",
        "description": "Set or update a word-count goal on the whole project, all books, a book, a chapter, or a section (never a scene). The active goal for that scope is updated, or a new one made; pass goalId to change a particular one. The target is the total words to reach, or with countMode additional the words to add from where it stands now. Personal unless shared is true.",
        "tags": [
          "goals"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GoalsSetResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "goals",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GoalsSetRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/goals/{goalId}/archive": {
      "post": {
        "operationId": "goals_archive",
        "summary": "Archive or restore a goal",
        "description": "Archive a goal, taking it out of the active and completed lists without deleting it, or restore an archived one with restore true.",
        "tags": [
          "goals"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GoalsArchiveResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "goalId",
            "in": "path",
            "required": true,
            "description": "Goal id from goals_get_progress.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "goals",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GoalsArchiveRequest"
              }
            }
          }
        }
      }
    },
    "/projects/{projectId}/versions": {
      "get": {
        "operationId": "history_list_versions",
        "summary": "List version history",
        "description": "List the project's saved versions, newest first: writing sessions, named versions, and the checkpoints sealed before a restore, each with when it ran, its revisions, and who wrote in it. Use a version id with history_read_doc, history_search, or history_bring_forward. Pass before to page further back.",
        "tags": [
          "versioning"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryListVersionsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Versions per page (default 20).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Page back: the endRev of the last version listed.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "x-dabble-capability": "view_versioning",
        "x-dabble-entitlement": "versioning"
      }
    },
    "/projects/{projectId}/versions/{versionId}/docs/{docId}": {
      "get": {
        "operationId": "history_read_doc",
        "summary": "Read a document at a version",
        "description": "Read a scene, chapter, character, or page as one saved version held it. Paginated like manuscript_read: pass the returned nextOffset to continue. Compare with the live text to see what changed, or find a passage with history_search first.",
        "tags": [
          "versioning"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryReadDocResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versionId",
            "in": "path",
            "required": true,
            "description": "Version id from history_list_versions or history_search.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id as it was in that version (ids are stable across versions).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "markdown",
                "text"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 500,
              "maximum": 60000
            }
          }
        ],
        "x-dabble-capability": "view_versioning",
        "x-dabble-entitlement": "versioning"
      }
    },
    "/projects/{projectId}/versions/search": {
      "get": {
        "operationId": "history_search",
        "summary": "Search version history for a passage",
        "description": "Find the most recent saved version that still contains a passage, when it has gone missing from the live project: quote a few distinctive words, optionally limit the search to one scene or chapter and its descendants. Checks the live project first, then versions newest first, a bounded number per call; pass the returned nextBefore to keep going back. Then read the version with history_read_doc or copy the document back with history_bring_forward.",
        "tags": [
          "versioning"
        ],
        "security": [
          {
            "oauth2": [
              "project:read"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistorySearchResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "project:read",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "quote",
            "in": "query",
            "required": true,
            "description": "Distinctive words from the missing passage.",
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 500
            }
          },
          {
            "name": "docId",
            "in": "query",
            "required": false,
            "description": "Search only this doc and its descendants (a scene, chapter, or book).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versions",
            "in": "query",
            "required": false,
            "description": "How many versions to check this call (default 10).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "Continue further back: the nextBefore from the previous call.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "x-dabble-capability": "view_versioning",
        "x-dabble-entitlement": "versioning"
      }
    },
    "/projects/{projectId}/versions/{versionId}/docs/{docId}/bring-forward": {
      "post": {
        "operationId": "history_bring_forward",
        "summary": "Bring a document forward from a version",
        "description": "Copy a scene, chapter, character, or page as a saved version held it into the Restored section of the project, as Bring Forward in the history panel does. The live document is untouched; the author merges the copy back by hand. The copy carries the text, title, subtitle, excerpt, label and colours; comment anchors, tracked-change marks (deletions resolved away), images, note cards, icon overlays and cover art are not carried over, and the result says what was left behind. Use history_search or history_read_doc first to pick the version.",
        "tags": [
          "versioning"
        ],
        "security": [
          {
            "oauth2": [
              "planning:write"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryBringForwardResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "x-dabble-scope": "planning:write",
        "parameters": [
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project id from dabble_list_projects.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "versionId",
            "in": "path",
            "required": true,
            "description": "Version id from history_list_versions or history_search.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "description": "Doc id as it was in that version.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-dabble-capability": "write",
        "x-dabble-entitlement": "versioning"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization code with PKCE. Clients may register dynamically.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://connect.dabblewriter.com/authorize",
            "tokenUrl": "https://connect.dabblewriter.com/token",
            "refreshUrl": "https://connect.dabblewriter.com/token",
            "scopes": {
              "project:read": "Read your projects: manuscript text, outline, plot grids, timelines, characters, places, notes, and comments; and see the images in your library.",
              "planning:write": "Add to, edit and reorganise your planning documents: plot grids, lines and points, timelines, tracks and events, characters, places, notebook pages, ideas, notes, scene summaries, labels, and comments; set where a scene happens and whose point of view it is; reorganise your manuscript: add, rename, move and remove parts, chapters and scenes; highlight passages; move documents to your trash; delete note cards and labels outright. Never a word of manuscript text.",
              "images:write": "Set, replace and remove the pictures on your planning documents: character portraits, the banners on characters, notebook pages, ideas and places, and the images on timeline events; and add to, rename and remove the images in your library. The app supplies each picture as a link, and Dabble keeps its own copy.",
              "manuscript:suggest": "Suggest edits to your manuscript text as tracked changes, which you accept or reject in Dabble, and withdraw its own suggestions. Words you accept are credited to Dabble Connect on your Certificate of Authorship."
            }
          }
        }
      },
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key the author created on their Connected Apps page, sent as a bearer token. It carries the scopes chosen when it was made."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error response.",
        "properties": {
          "error": {
            "type": "string",
            "description": "A machine-readable code.",
            "enum": [
              "invalid",
              "forbidden",
              "not_found",
              "too_large",
              "limit",
              "internal",
              "upstream",
              "unavailable",
              "unauthorized",
              "insufficient_scope",
              "subscription_required",
              "feature_unavailable"
            ]
          },
          "message": {
            "type": "string",
            "description": "What went wrong, written for the person using the integration."
          },
          "details": {
            "description": "Structured context, when there is any: validation issues, for example."
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "DabbleWhoamiResponse": {
        "type": "object",
        "properties": {
          "uid": {
            "type": "string",
            "description": "The Dabble account this connection acts as."
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "app": {
            "type": "string",
            "description": "The app or API key this connection was granted to."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "project:read",
                "planning:write",
                "images:write",
                "manuscript:suggest"
              ]
            }
          },
          "environment": {
            "type": "string",
            "enum": [
              "production",
              "test",
              "local"
            ]
          }
        },
        "required": [
          "uid",
          "app",
          "scopes",
          "environment"
        ],
        "additionalProperties": false
      },
      "DabbleListProjectsResponse": {
        "type": "object",
        "properties": {
          "projects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "description": "Project type: novel, ideas, …"
                },
                "section": {
                  "type": "string",
                  "enum": [
                    "active",
                    "archive",
                    "trash",
                    "templates",
                    "personal",
                    "unsorted"
                  ]
                },
                "role": {
                  "type": "string",
                  "description": "Your role on the project: owner, write, edit, comment, view, or unknown."
                },
                "modifiedAt": {
                  "description": "ISO 8601.",
                  "type": "string"
                },
                "lastOpenedAt": {
                  "description": "ISO 8601.",
                  "type": "string"
                },
                "isBranch": {
                  "type": "boolean",
                  "description": "True for a review copy."
                },
                "branchName": {
                  "type": "string"
                },
                "books": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Book titles in manuscript order."
                }
              },
              "required": [
                "id",
                "title",
                "type",
                "section",
                "role",
                "isBranch",
                "books"
              ],
              "additionalProperties": false
            }
          },
          "total": {
            "type": "number",
            "description": "Projects in the requested sections, before the limit was applied."
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "projects",
          "total",
          "truncated"
        ],
        "additionalProperties": false
      },
      "ChapterOutline": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "part",
              "chapter",
              "page"
            ]
          },
          "title": {
            "type": "string"
          },
          "words": {
            "type": "number"
          },
          "scenes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "words": {
                  "type": "number"
                },
                "summary": {
                  "type": "string"
                },
                "labels": {
                  "description": "The texts of the labels on the scene.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "notes": {
                  "type": "number",
                  "description": "Note cards on the scene."
                },
                "openComments": {
                  "type": "number",
                  "description": "Unresolved comment threads on the scene."
                }
              },
              "required": [
                "id",
                "title",
                "words",
                "summary",
                "notes",
                "openComments"
              ],
              "additionalProperties": false
            }
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChapterOutline"
            }
          }
        },
        "required": [
          "id",
          "kind",
          "title",
          "words",
          "scenes",
          "children"
        ],
        "additionalProperties": false
      },
      "NotebookOutline": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "folder",
              "page"
            ]
          },
          "words": {
            "type": "number"
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotebookOutline"
            }
          }
        },
        "required": [
          "id",
          "title",
          "kind",
          "children"
        ],
        "additionalProperties": false
      },
      "IdeasOutline": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "folder",
              "idea",
              "image"
            ]
          },
          "subtitle": {
            "description": "The one-line description an idea carries.",
            "type": "string"
          },
          "words": {
            "type": "number"
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IdeasOutline"
            }
          }
        },
        "required": [
          "id",
          "title",
          "kind",
          "children"
        ],
        "additionalProperties": false
      },
      "DabbleGetOutlineResponse": {
        "type": "object",
        "properties": {
          "projectId": {
            "type": "string"
          },
          "books": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "subtitle": {
                  "type": "string"
                },
                "author": {
                  "type": "string"
                },
                "words": {
                  "type": "number"
                },
                "chapters": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ChapterOutline"
                  }
                }
              },
              "required": [
                "id",
                "title",
                "words",
                "chapters"
              ],
              "additionalProperties": false
            }
          },
          "plots": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "bookId": {
                  "type": "string"
                },
                "bookTitle": {
                  "type": "string"
                },
                "lines": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "points": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "id",
                      "title",
                      "points"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "id",
                "title",
                "lines"
              ],
              "additionalProperties": false
            }
          },
          "casts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "characters": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "title"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "id",
                "title",
                "characters"
              ],
              "additionalProperties": false
            }
          },
          "notebook": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotebookOutline"
            }
          },
          "ideas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IdeasOutline"
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "books": {
                "type": "number"
              },
              "scenes": {
                "type": "number"
              },
              "words": {
                "type": "number"
              },
              "characters": {
                "type": "number"
              },
              "pages": {
                "type": "number"
              },
              "ideas": {
                "type": "number"
              }
            },
            "required": [
              "books",
              "scenes",
              "words",
              "characters",
              "pages",
              "ideas"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "projectId",
          "books",
          "plots",
          "casts",
          "notebook",
          "ideas",
          "totals"
        ],
        "additionalProperties": false
      },
      "DabbleSearchResponse": {
        "type": "object",
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "docId": {
                  "type": "string"
                },
                "docType": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "field": {
                  "type": "string",
                  "enum": [
                    "body",
                    "summary",
                    "note",
                    "title"
                  ],
                  "description": "Where the match is."
                },
                "noteId": {
                  "description": "The note card, when the match is in one.",
                  "type": "string"
                },
                "snippet": {
                  "type": "string",
                  "description": "The match in [[double brackets]] with context either side."
                },
                "index": {
                  "type": "number",
                  "description": "Character offset of the match in the field’s plain text."
                }
              },
              "required": [
                "docId",
                "docType",
                "title",
                "field",
                "snippet",
                "index"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "matches"
        ],
        "additionalProperties": false
      },
      "DabbleListLabelsResponse": {
        "type": "object",
        "properties": {
          "labels": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "color": {
                      "type": "string"
                    }
                  },
                  "additionalProperties": false
                },
                "docs": {
                  "type": "number",
                  "description": "Live docs wearing the label."
                },
                "notes": {
                  "type": "number",
                  "description": "Note cards wearing the label."
                }
              },
              "required": [
                "label",
                "docs",
                "notes"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "labels"
        ],
        "additionalProperties": false
      },
      "DabbleSetLabelRequest": {
        "type": "object",
        "properties": {
          "text": {
            "description": "Label text, e.g. \"Needs research\".",
            "type": "string",
            "maxLength": 60
          },
          "color": {
            "description": "One of: navy, blue, teal, green, yellow, amber, orange, coral, red, raspberry, pink, lavender, purple, taupe, brown, black.",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          },
          "replace": {
            "description": "Make this the doc's only label instead of adding it.",
            "type": "boolean"
          },
          "clear": {
            "description": "Take the given label off the doc instead of adding it; with no text or colour, take every label off.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DabbleSetLabelResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "labels": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "text": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                }
              },
              "additionalProperties": false
            },
            "description": "The labels now on the doc, in order."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "labels",
          "rev"
        ],
        "additionalProperties": false
      },
      "DabbleUpdateLabelRequest": {
        "type": "object",
        "properties": {
          "text": {
            "description": "Current label text (omit for a colour-only label).",
            "type": "string",
            "maxLength": 60
          },
          "color": {
            "description": "Current label colour (omit for a text-only label).",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          },
          "newText": {
            "description": "The new text.",
            "type": "string",
            "maxLength": 60
          },
          "newColor": {
            "description": "The new colour.",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          }
        },
        "additionalProperties": false
      },
      "DabbleUpdateLabelResponse": {
        "type": "object",
        "properties": {
          "docs": {
            "type": "number",
            "description": "Docs changed."
          },
          "notes": {
            "type": "number",
            "description": "Note cards changed."
          },
          "registry": {
            "type": "number",
            "description": "Project label list entries changed."
          },
          "outOfReach": {
            "type": "number",
            "description": "Docs in the trash or archive left as they were."
          },
          "unwritable": {
            "type": "number",
            "description": "Docs Connect cannot edit (an image page) left as they were."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docs",
          "notes",
          "registry",
          "outOfReach",
          "unwritable",
          "rev"
        ],
        "additionalProperties": false
      },
      "DabbleDeleteLabelRequest": {
        "type": "object",
        "properties": {
          "text": {
            "description": "Label text (omit for a colour-only label).",
            "type": "string",
            "maxLength": 60
          },
          "color": {
            "description": "Label colour (omit for a text-only label).",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          }
        },
        "additionalProperties": false
      },
      "DabbleDeleteLabelResponse": {
        "type": "object",
        "properties": {
          "docs": {
            "type": "number",
            "description": "Docs changed."
          },
          "notes": {
            "type": "number",
            "description": "Note cards changed."
          },
          "registry": {
            "type": "number",
            "description": "Project label list entries changed."
          },
          "outOfReach": {
            "type": "number",
            "description": "Docs in the trash or archive left as they were."
          },
          "unwritable": {
            "type": "number",
            "description": "Docs Connect cannot edit (an image page) left as they were."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docs",
          "notes",
          "registry",
          "outOfReach",
          "unwritable",
          "rev"
        ],
        "additionalProperties": false
      },
      "DabbleMoveDocRequest": {
        "type": "object",
        "properties": {
          "parentId": {
            "description": "Destination: a folder, character, place, cast, family tree, hierarchy, chapter, blank section, book, part, or a section by its id (\"characters\", \"locations\", \"notebook\"). Omit to keep the current parent.",
            "type": "string"
          },
          "position": {
            "description": "Position among the destination's children, 1-based. Omit for the end.",
            "type": "integer",
            "minimum": 1
          }
        },
        "additionalProperties": false
      },
      "DabbleMoveDocResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "fromId": {
            "type": "string",
            "description": "The parent it left."
          },
          "parentId": {
            "type": "string",
            "description": "The parent it is under now."
          },
          "position": {
            "type": "number",
            "description": "Its position among the siblings, 1-based."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "fromId",
          "parentId",
          "position",
          "rev"
        ],
        "additionalProperties": false
      },
      "DabbleSetIconOverlayRequest": {
        "type": "object",
        "properties": {
          "overlay": {
            "type": "string",
            "enum": [
              "none",
              "check",
              "remove",
              "eye",
              "edit",
              "lock"
            ],
            "description": "One of: none, check, remove, eye, edit, lock. \"none\" clears the overlay."
          }
        },
        "required": [
          "overlay"
        ],
        "additionalProperties": false
      },
      "DabbleSetIconOverlayResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "overlay": {
            "type": "string",
            "enum": [
              "none",
              "check",
              "remove",
              "eye",
              "edit",
              "lock"
            ],
            "description": "One of: none, check, remove, eye, edit, lock. \"none\" clears the overlay."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "overlay",
          "rev"
        ],
        "additionalProperties": false
      },
      "ManuscriptReadResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "manuscripts_scene, manuscripts_chapter, manuscripts_part, or manuscripts_book."
          },
          "title": {
            "type": "string"
          },
          "bookId": {
            "type": "string"
          },
          "chapterId": {
            "type": "string"
          },
          "words": {
            "type": "number"
          },
          "summary": {
            "type": "string"
          },
          "text": {
            "type": "string",
            "description": "This page of the text."
          },
          "offset": {
            "type": "number",
            "description": "Character offset this page starts at."
          },
          "nextOffset": {
            "description": "Offset to continue from, or null when this page is the last.",
            "type": [
              "number",
              "null"
            ]
          },
          "totalLength": {
            "type": "number",
            "description": "Length of the whole text in characters."
          },
          "rev": {
            "type": "number",
            "description": "The project revision the text was read at; pass it back to continue."
          },
          "format": {
            "type": "string",
            "enum": [
              "markdown",
              "text"
            ]
          },
          "view": {
            "type": "string",
            "enum": [
              "final",
              "original"
            ]
          }
        },
        "required": [
          "docId",
          "type",
          "title",
          "words",
          "summary",
          "text",
          "offset",
          "nextOffset",
          "totalLength",
          "rev",
          "format",
          "view"
        ],
        "additionalProperties": false
      },
      "ManuscriptSetSummaryRequest": {
        "type": "object",
        "properties": {
          "summary": {
            "type": "string",
            "maxLength": 5000,
            "description": "The new summary. Empty clears it."
          }
        },
        "required": [
          "summary"
        ],
        "additionalProperties": false
      },
      "ManuscriptSetSummaryResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "ManuscriptCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "part",
              "chapter",
              "blank",
              "scene"
            ],
            "description": "What to add. A blank section is an unnumbered one, such as a prologue."
          },
          "parentId": {
            "type": "string",
            "description": "The book, part, chapter or blank section it goes in, from dabble_get_outline."
          },
          "position": {
            "description": "Where it lands among its siblings, 1 being first. Omit for the end.",
            "type": "integer",
            "minimum": 1
          },
          "title": {
            "description": "Its title. Omit to let Dabble number a chapter or name a scene by its opening line.",
            "type": "string",
            "maxLength": 300
          },
          "summary": {
            "description": "Its summary, shown on its card and in the plot grid.",
            "type": "string",
            "maxLength": 5000
          },
          "scenes": {
            "description": "For a chapter or blank section: the scenes it starts with, in order. Defaults to one untitled scene. Each summary is at most 1250 characters.",
            "minItems": 1,
            "maxItems": 12,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string",
                  "maxLength": 300
                },
                "summary": {
                  "type": "string",
                  "maxLength": 1250
                }
              }
            }
          }
        },
        "required": [
          "type",
          "parentId"
        ],
        "additionalProperties": false
      },
      "ManuscriptCreateResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "created": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "title": {
                  "description": "Omitted when the doc has no title of its own.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "type"
              ],
              "additionalProperties": false
            },
            "description": "Every document created, the new one first, then what it holds in reading order."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "parentId",
          "created",
          "rev"
        ],
        "additionalProperties": false
      },
      "ManuscriptRenameRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "The new title. Empty clears it.",
            "type": "string",
            "maxLength": 300
          },
          "subtitle": {
            "description": "A book's subtitle. Books only.",
            "type": "string",
            "maxLength": 300
          }
        },
        "additionalProperties": false
      },
      "ManuscriptRenameResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "title",
                "subtitle"
              ]
            },
            "description": "What changed; empty when it already had that name."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          },
          "dashboardMirrorFailed": {
            "description": "True when a book rename could not be mirrored into the dashboard index; its name there may revert until the author next opens the project and re-syncs it.",
            "type": "boolean"
          }
        },
        "required": [
          "docId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "ManuscriptRemoveResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HighlightListResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "highlights": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "docId": {
                  "type": "string"
                },
                "docTitle": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "occurrence": {
                  "type": "number",
                  "description": "Which occurrence of the text in the doc this is, 1-based."
                }
              },
              "required": [
                "docId",
                "docTitle",
                "color",
                "text",
                "occurrence"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "docId",
          "highlights"
        ],
        "additionalProperties": false
      },
      "HighlightSetRequest": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "The passage, quoted exactly as manuscript_read shows it."
          },
          "occurrence": {
            "description": "Which occurrence (1-based) when the passage repeats.",
            "type": "integer",
            "minimum": 1
          },
          "color": {
            "type": "string",
            "enum": [
              "yellow",
              "purple",
              "teal",
              "green",
              "blue",
              "black"
            ],
            "description": "One of: yellow, purple, teal, green, blue, black. Black is redaction."
          }
        },
        "required": [
          "quote",
          "color"
        ],
        "additionalProperties": false
      },
      "HighlightSetResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "enum": [
              "yellow",
              "purple",
              "teal",
              "green",
              "blue",
              "black"
            ]
          },
          "length": {
            "type": "number",
            "description": "Characters highlighted."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "color",
          "length",
          "rev"
        ],
        "additionalProperties": false
      },
      "HighlightRemoveRequest": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "The passage, quoted exactly as manuscript_read shows it."
          },
          "occurrence": {
            "description": "Which occurrence (1-based) when the passage repeats.",
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "quote"
        ],
        "additionalProperties": false
      },
      "HighlightRemoveResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "length": {
            "type": "number",
            "description": "Characters cleared."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "length",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotListGridsResponse": {
        "type": "object",
        "properties": {
          "grids": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "linkedBookId": {
                  "type": "string"
                },
                "linkedBookTitle": {
                  "type": "string"
                },
                "lines": {
                  "type": "number",
                  "description": "Plot lines on the grid."
                }
              },
              "required": [
                "id",
                "title",
                "lines"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "grids"
        ],
        "additionalProperties": false
      },
      "PlotGetGridResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "linkedBookId": {
            "type": "string"
          },
          "linkedBookTitle": {
            "type": "string"
          },
          "lines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "points": {
                  "type": "number"
                }
              },
              "required": [
                "id",
                "title",
                "points"
              ],
              "additionalProperties": false
            }
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "row": {
                  "type": "number",
                  "description": "Grid row, 1-based."
                },
                "sceneId": {
                  "description": "The scene this row follows, on a grid linked to a book.",
                  "type": "string"
                },
                "sceneTitle": {
                  "type": "string"
                },
                "cells": {
                  "type": "object",
                  "propertyNames": {
                    "type": "string"
                  },
                  "additionalProperties": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "body": {
                        "type": "string",
                        "description": "The card text as plain text."
                      },
                      "labels": {
                        "description": "The texts of the labels on the card.",
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "required": [
                      "id",
                      "title",
                      "body"
                    ],
                    "additionalProperties": false
                  },
                  "description": "Plot line id → the point in that cell."
                }
              },
              "required": [
                "row",
                "cells"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "id",
          "title",
          "lines",
          "rows"
        ],
        "additionalProperties": false
      },
      "PlotCreateLineRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "The plot line name."
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "PlotCreateLineResponse": {
        "type": "object",
        "properties": {
          "lineId": {
            "type": "string"
          },
          "plotId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "lineId",
          "plotId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotCreatePointRequest": {
        "type": "object",
        "properties": {
          "lineId": {
            "type": "string",
            "description": "Plot line id from plot_get_grid or plot_create_line."
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "The card title."
          },
          "description": {
            "description": "The card text. Plain text or light Markdown.",
            "type": "string",
            "maxLength": 5000
          },
          "row": {
            "description": "Grid row (1-based) as plot_get_grid reports.",
            "type": "integer",
            "minimum": 1
          },
          "sceneId": {
            "description": "Scene id to align the point with (linked grids only).",
            "type": "string"
          }
        },
        "required": [
          "lineId",
          "title"
        ],
        "additionalProperties": false
      },
      "PlotCreatePointResponse": {
        "type": "object",
        "properties": {
          "pointId": {
            "type": "string"
          },
          "lineId": {
            "type": "string"
          },
          "plotId": {
            "type": "string"
          },
          "row": {
            "type": "number",
            "description": "The row the point landed on, 1-based."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pointId",
          "lineId",
          "plotId",
          "row",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotUpdatePointRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "description": {
            "description": "New card text. Empty clears it.",
            "type": "string",
            "maxLength": 5000
          }
        },
        "additionalProperties": false
      },
      "PlotUpdatePointResponse": {
        "type": "object",
        "properties": {
          "pointId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pointId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotMovePointRequest": {
        "type": "object",
        "properties": {
          "lineId": {
            "description": "The plot line to move onto. Omit to stay on its line.",
            "type": "string"
          },
          "row": {
            "description": "Grid row (1-based) as plot_get_grid reports.",
            "type": "integer",
            "minimum": 1
          },
          "sceneId": {
            "description": "Scene id to align the point with (linked grids only).",
            "type": "string"
          },
          "swap": {
            "description": "Exchange places with the point already on the target row.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PlotMovePointResponse": {
        "type": "object",
        "properties": {
          "pointId": {
            "type": "string"
          },
          "from": {
            "type": "object",
            "properties": {
              "lineId": {
                "type": "string"
              },
              "row": {
                "type": "number"
              }
            },
            "required": [
              "lineId",
              "row"
            ],
            "additionalProperties": false
          },
          "to": {
            "type": "object",
            "properties": {
              "lineId": {
                "type": "string"
              },
              "row": {
                "type": "number"
              }
            },
            "required": [
              "lineId",
              "row"
            ],
            "additionalProperties": false
          },
          "swapped": {
            "description": "The point that took the source cell in a swap.",
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pointId",
          "from",
          "to",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotRemovePointResponse": {
        "type": "object",
        "properties": {
          "pointId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pointId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotUpdateLineRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "The new name."
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "PlotUpdateLineResponse": {
        "type": "object",
        "properties": {
          "lineId": {
            "type": "string"
          },
          "plotId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "lineId",
          "plotId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotMoveLineRequest": {
        "type": "object",
        "properties": {
          "position": {
            "type": "integer",
            "minimum": 1,
            "description": "The new position among the plot lines, 1-based."
          }
        },
        "required": [
          "position"
        ],
        "additionalProperties": false
      },
      "PlotMoveLineResponse": {
        "type": "object",
        "properties": {
          "lineId": {
            "type": "string"
          },
          "plotId": {
            "type": "string"
          },
          "from": {
            "type": "number",
            "description": "Position before, 1-based."
          },
          "to": {
            "type": "number",
            "description": "Position after, 1-based."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "lineId",
          "plotId",
          "from",
          "to",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotRemoveLineResponse": {
        "type": "object",
        "properties": {
          "lineId": {
            "type": "string"
          },
          "plotId": {
            "type": "string"
          },
          "points": {
            "type": "number",
            "description": "Plot points that went to the trash with the line."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "lineId",
          "plotId",
          "points",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotCreateGridRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "The grid name. Omit for the default.",
            "type": "string",
            "maxLength": 300
          }
        },
        "additionalProperties": false
      },
      "PlotCreateGridResponse": {
        "type": "object",
        "properties": {
          "plotId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "plotId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotRemoveGridResponse": {
        "type": "object",
        "properties": {
          "plotId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "plotId",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotLinkBookRequest": {
        "type": "object",
        "properties": {
          "bookId": {
            "type": "string",
            "description": "Book id from dabble_get_outline."
          }
        },
        "required": [
          "bookId"
        ],
        "additionalProperties": false
      },
      "PlotLinkBookResponse": {
        "type": "object",
        "properties": {
          "plotId": {
            "type": "string"
          },
          "bookId": {
            "type": "string"
          },
          "scenes": {
            "type": "number",
            "description": "Scene rows the grid now follows."
          },
          "relinked": {
            "type": "boolean",
            "description": "True when the grid was moved from another book."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "plotId",
          "bookId",
          "scenes",
          "relinked",
          "rev"
        ],
        "additionalProperties": false
      },
      "PlotUnlinkBookResponse": {
        "type": "object",
        "properties": {
          "plotId": {
            "type": "string"
          },
          "bookId": {
            "description": "The book it was linked to.",
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "plotId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineListResponse": {
        "type": "object",
        "properties": {
          "timelines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "calendar": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "gregorian",
                        "relative",
                        "custom"
                      ]
                    },
                    "name": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "kind",
                    "name"
                  ],
                  "additionalProperties": false
                },
                "bookId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "book": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "tracks": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "color": {
                        "type": "string"
                      },
                      "time": {
                        "type": "string",
                        "description": "The time its dates are written in: the timeline’s, a zone of it, or another calendar."
                      }
                    },
                    "required": [
                      "id",
                      "title",
                      "time"
                    ],
                    "additionalProperties": false
                  }
                },
                "events": {
                  "type": "number"
                },
                "undated": {
                  "type": "number"
                },
                "first": {
                  "description": "The date of its first event.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "last": {
                  "description": "The date of its last event.",
                  "type": [
                    "string",
                    "null"
                  ]
                }
              },
              "required": [
                "id",
                "title",
                "calendar",
                "bookId",
                "book",
                "tracks",
                "events",
                "undated",
                "first",
                "last"
              ],
              "additionalProperties": false
            }
          },
          "calendars": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "custom",
                    "relative"
                  ]
                },
                "lineUp": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "day": {
                          "type": "string",
                          "description": "A day in this calendar, in its words."
                        },
                        "sameDay": {
                          "type": "string",
                          "description": "The same day in the other calendar, in its words."
                        },
                        "calendarId": {
                          "type": "string",
                          "description": "\"gregorian\", or the other calendar’s id."
                        },
                        "calendar": {
                          "type": "string",
                          "description": "The other calendar’s name."
                        }
                      },
                      "required": [
                        "day",
                        "sameDay",
                        "calendarId",
                        "calendar"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Where it stands against another calendar: one day named in both. Null for none."
                }
              },
              "required": [
                "id",
                "name",
                "kind",
                "lineUp"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "timelines",
          "calendars"
        ],
        "additionalProperties": false
      },
      "TimelineGetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "calendar": {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "gregorian",
                  "relative",
                  "custom"
                ]
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "kind",
              "name"
            ],
            "additionalProperties": false
          },
          "bookId": {
            "type": [
              "string",
              "null"
            ]
          },
          "tracks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "time": {
                  "type": "string",
                  "description": "The time its dates are written in: the timeline’s, a zone of it, or another calendar."
                }
              },
              "required": [
                "id",
                "title",
                "time"
              ],
              "additionalProperties": false
            }
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "timelineId": {
                  "type": "string"
                },
                "when": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string",
                          "description": "The date in its calendar’s words."
                        },
                        "parts": {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "text",
                        "parts"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string",
                          "description": "The date in its calendar’s words."
                        },
                        "parts": {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "text",
                        "parts"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "at": {
                  "description": "Where it sits on the timeline, for ordering: days since the calendar’s start.",
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "trackId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "track": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "characters": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "mentioned": {
                        "type": "boolean",
                        "description": "In the event because its notes @mention them."
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "mentioned"
                    ],
                    "additionalProperties": false
                  }
                },
                "scenes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "title": {
                        "type": "string"
                      },
                      "role": {
                        "type": "string",
                        "enum": [
                          "present",
                          "flashback"
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "title"
                    ],
                    "additionalProperties": false
                  }
                },
                "place": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "path": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "path"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "weather": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "clear",
                        "partly-cloudy",
                        "cloudy",
                        "rain",
                        "storm",
                        "tornado",
                        "flood",
                        "snow",
                        "blizzard",
                        "fog",
                        "wind"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The weather it starts in."
                },
                "weatherChanges": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "at": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string"
                          },
                          "parts": {
                            "type": "object",
                            "properties": {
                              "era": {
                                "description": "Custom calendars only: the index of the era the year counts in.",
                                "type": "integer"
                              },
                              "year": {
                                "type": "integer"
                              },
                              "month": {
                                "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                                "type": "integer"
                              },
                              "day": {
                                "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                                "type": "integer"
                              },
                              "hour": {
                                "type": "integer"
                              },
                              "minute": {
                                "type": "integer"
                              }
                            },
                            "additionalProperties": false
                          }
                        },
                        "required": [
                          "text",
                          "parts"
                        ],
                        "additionalProperties": false
                      },
                      "weather": {
                        "anyOf": [
                          {
                            "type": "string",
                            "enum": [
                              "clear",
                              "partly-cloudy",
                              "cloudy",
                              "rain",
                              "storm",
                              "tornado",
                              "flood",
                              "snow",
                              "blizzard",
                              "fog",
                              "wind"
                            ]
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "at",
                      "weather"
                    ],
                    "additionalProperties": false
                  },
                  "description": "Where its weather changes while it runs, in order: the moment, and the weather from then on."
                },
                "imageUrl": {
                  "description": "The image across the top of its card; set it with images_set_banner.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "followsEventId": {
                  "description": "The event its date is counted from, when it is.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "appearsOn": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Other timelines it shows on."
                },
                "notes": {
                  "type": "string"
                },
                "statusChanges": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "characterId": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "born",
                          "died",
                          "missing",
                          "companion_start",
                          "companion_end"
                        ]
                      },
                      "companionId": {
                        "type": "string"
                      },
                      "companionName": {
                        "type": "string"
                      },
                      "descriptor": {
                        "type": "string"
                      },
                      "why": {
                        "type": "string",
                        "enum": [
                          "released",
                          "transferred",
                          "destroyed",
                          "died"
                        ]
                      }
                    },
                    "required": [
                      "characterId",
                      "name",
                      "status"
                    ],
                    "additionalProperties": false
                  },
                  "description": "Who is born, dies or goes missing at it, and whose companion tie begins or ends here (characterId the character, companionId the companion), as Change Status… sets it in Dabble (kept on each character and companion link: family_get, family_set_life and family_set_companion read and set the same). Only where the plan has family trees."
                },
                "age": {
                  "description": "Read with characterId: how old they are at its start, in whole years of the calendar their life is written in.",
                  "type": [
                    "number",
                    "null"
                  ]
                }
              },
              "required": [
                "id",
                "title",
                "timelineId",
                "when",
                "until",
                "at",
                "trackId",
                "track",
                "characters",
                "scenes",
                "place",
                "weather",
                "weatherChanges",
                "imageUrl",
                "followsEventId",
                "appearsOn",
                "notes"
              ],
              "additionalProperties": false
            }
          },
          "total": {
            "type": "number",
            "description": "Events that match, before paging."
          },
          "offset": {
            "type": "number"
          },
          "character": {
            "description": "The character narrowed to, with when they were born and died where the timeline keeps it.",
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "born": {
                "description": "In the words of the calendar their life is written in.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "died": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "bornAt": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The place they were born."
              },
              "diedAt": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "name"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The place they died."
              },
              "calendar": {
                "description": "The calendar their life is written in; null for one that keeps none, read in each timeline's own.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "onTracks": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "trackId": {
                      "description": "Null for the timeline's own time.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "track": {
                      "type": "string"
                    },
                    "calendar": {
                      "type": "string"
                    },
                    "born": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "died": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "trackId",
                    "track",
                    "calendar",
                    "born",
                    "died"
                  ],
                  "additionalProperties": false
                },
                "description": "The dates as the timeline and each of its tracks read them. Empty where nothing lines their calendar up."
              }
            },
            "required": [
              "id",
              "name",
              "born",
              "died",
              "bornAt",
              "diedAt",
              "calendar",
              "onTracks"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "title",
          "calendar",
          "bookId",
          "tracks",
          "events",
          "total",
          "offset"
        ],
        "additionalProperties": false
      },
      "TimelineGetEventResponse": {
        "type": "object",
        "properties": {
          "event": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "timelineId": {
                "type": "string"
              },
              "when": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "until": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "at": {
                "description": "Where it sits on the timeline, for ordering: days since the calendar’s start.",
                "type": [
                  "number",
                  "null"
                ]
              },
              "trackId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "track": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "characters": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "mentioned": {
                      "type": "boolean",
                      "description": "In the event because its notes @mention them."
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "mentioned"
                  ],
                  "additionalProperties": false
                }
              },
              "scenes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "present",
                        "flashback"
                      ]
                    }
                  },
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": false
                }
              },
              "place": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "path": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "path"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "weather": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "clear",
                      "partly-cloudy",
                      "cloudy",
                      "rain",
                      "storm",
                      "tornado",
                      "flood",
                      "snow",
                      "blizzard",
                      "fog",
                      "wind"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The weather it starts in."
              },
              "weatherChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string"
                        },
                        "parts": {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "text",
                        "parts"
                      ],
                      "additionalProperties": false
                    },
                    "weather": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "clear",
                            "partly-cloudy",
                            "cloudy",
                            "rain",
                            "storm",
                            "tornado",
                            "flood",
                            "snow",
                            "blizzard",
                            "fog",
                            "wind"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "at",
                    "weather"
                  ],
                  "additionalProperties": false
                },
                "description": "Where its weather changes while it runs, in order: the moment, and the weather from then on."
              },
              "imageUrl": {
                "description": "The image across the top of its card; set it with images_set_banner.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "followsEventId": {
                "description": "The event its date is counted from, when it is.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "appearsOn": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Other timelines it shows on."
              },
              "notes": {
                "type": "string"
              },
              "statusChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "characterId": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "born",
                        "died",
                        "missing",
                        "companion_start",
                        "companion_end"
                      ]
                    },
                    "companionId": {
                      "type": "string"
                    },
                    "companionName": {
                      "type": "string"
                    },
                    "descriptor": {
                      "type": "string"
                    },
                    "why": {
                      "type": "string",
                      "enum": [
                        "released",
                        "transferred",
                        "destroyed",
                        "died"
                      ]
                    }
                  },
                  "required": [
                    "characterId",
                    "name",
                    "status"
                  ],
                  "additionalProperties": false
                },
                "description": "Who is born, dies or goes missing at it, and whose companion tie begins or ends here (characterId the character, companionId the companion), as Change Status… sets it in Dabble (kept on each character and companion link: family_get, family_set_life and family_set_companion read and set the same). Only where the plan has family trees."
              },
              "age": {
                "description": "Read with characterId: how old they are at its start, in whole years of the calendar their life is written in.",
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "title",
              "timelineId",
              "when",
              "until",
              "at",
              "trackId",
              "track",
              "characters",
              "scenes",
              "place",
              "weather",
              "weatherChanges",
              "imageUrl",
              "followsEventId",
              "appearsOn",
              "notes"
            ],
            "additionalProperties": false
          },
          "timeline": {
            "type": "string"
          }
        },
        "required": [
          "event",
          "timeline"
        ],
        "additionalProperties": false
      },
      "TimelineCreateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "calendar": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "gregorian"
                  }
                },
                "required": [
                  "kind"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "relative"
                  },
                  "zeroLabel": {
                    "description": "What Day 0 is.",
                    "type": "string",
                    "maxLength": 300
                  }
                },
                "required": [
                  "kind"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "custom"
                  },
                  "calendarId": {
                    "type": "string",
                    "description": "A calendar id from timeline_list."
                  }
                },
                "required": [
                  "kind",
                  "calendarId"
                ]
              }
            ]
          },
          "bookId": {
            "description": "The book it is for, from dabble_get_outline.",
            "type": "string"
          },
          "trackTitle": {
            "description": "The name of its first track. Default \"Events\".",
            "type": "string",
            "maxLength": 300
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "TimelineCreateResponse": {
        "type": "object",
        "properties": {
          "timelineId": {
            "type": "string"
          },
          "trackId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "timelineId",
          "trackId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineUpdateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "bookId": {
            "description": "The book it is for; null for none.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "TimelineUpdateResponse": {
        "type": "object",
        "properties": {
          "timelineId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "timelineId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineRemoveResponse": {
        "type": "object",
        "properties": {
          "timelineId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "timelineId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineCreateTrackRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "color": {
            "description": "One of Dabble’s colours. Omit for one the timeline’s tracks do not wear yet.",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "TimelineCreateTrackResponse": {
        "type": "object",
        "properties": {
          "trackId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "trackId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineUpdateTrackRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "color": {
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ]
          }
        },
        "additionalProperties": false
      },
      "TimelineUpdateTrackResponse": {
        "type": "object",
        "properties": {
          "trackId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "trackId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineRemoveTrackResponse": {
        "type": "object",
        "properties": {
          "trackId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "trackId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineCreateEventRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "when": {
            "description": "When it starts. Null makes it undated.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "description": "When it ends, for an event that lasts. Null makes it a moment.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "trackId": {
            "description": "The track to put it on, from timeline_get. Default: the first track (a timeline with none is given one).",
            "type": "string"
          },
          "characterIds": {
            "description": "The characters in it, from character_list; replaces the list. Characters its notes @mention are in it too.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sceneIds": {
            "description": "The scenes it happens in, from dabble_get_outline; replaces the list.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sceneRoles": {
            "description": "How it is in a scene it happens in: the scene's present, or a flashback (or flash-forward) the scene looks to. Null leaves it to the dates, as Dabble does by default.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sceneId": {
                  "type": "string"
                },
                "role": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "present",
                        "flashback"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "sceneId",
                "role"
              ]
            }
          },
          "appearsOn": {
            "description": "Other timelines on the same calendar it shows on as well, from timeline_list; replaces the list. It is never copied.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "placeId": {
            "description": "The place it happens at, from location_list. Null clears it.",
            "type": [
              "string",
              "null"
            ]
          },
          "weather": {
            "description": "The weather it happens in, or starts in where it changes. Null clears it.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "clear",
                  "partly-cloudy",
                  "cloudy",
                  "rain",
                  "storm",
                  "tornado",
                  "flood",
                  "snow",
                  "blizzard",
                  "fog",
                  "wind"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "weatherChanges": {
            "description": "Where the weather changes while the event runs, replacing the list: an event that lasts (with an end) only. Null or [] clears them, leaving the one weather throughout.",
            "anyOf": [
              {
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 200
                        },
                        {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          }
                        }
                      ],
                      "description": "When the weather changes: a moment while the event runs, after its start and before its end, in its calendar (\"16 Mar 1854 15:00\")."
                    },
                    "weather": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "clear",
                            "partly-cloudy",
                            "cloudy",
                            "rain",
                            "storm",
                            "tornado",
                            "flood",
                            "snow",
                            "blizzard",
                            "fog",
                            "wind"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "The weather from then on; null where it clears to none."
                    }
                  },
                  "required": [
                    "at",
                    "weather"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "notes": {
            "description": "Its notes, replacing what is there. Plain text or light Markdown; @[Name](id) mentions a character.",
            "type": "string",
            "maxLength": 20000
          },
          "statusChanges": {
            "description": "Who is born, dies or goes missing at this event, and whose companion tie begins or ends here, written as Change Status… writes it in Dabble: on the character (or their companion link), at this event, so the family tree shows the change here. Replaces the event's list; null clears it. A status a character has at another moment moves here; a death also sets their Died date to the event's day; a companion tie that began or ended here and is left out begins before the story, or lasts, again. An event in no scene is placed in the story by its date. Needs family trees.",
            "anyOf": [
              {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "characterId": {
                      "type": "string",
                      "description": "Character id from character_list (for a companion change: whose companion)."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "born",
                        "died",
                        "missing",
                        "companion_start",
                        "companion_end"
                      ],
                      "description": "born, died or missing: what happens to them at this event, as Change Status… says it. companion_start or companion_end: their tie to companionId begins or ends here."
                    },
                    "companionId": {
                      "description": "For a companion change: the companion, from character_list.",
                      "type": "string"
                    },
                    "descriptor": {
                      "description": "For companion_start: what the companion is to them (\"Link AI\"); left out keeps what is there.",
                      "type": "string",
                      "maxLength": 40
                    },
                    "why": {
                      "description": "For companion_end: why it ends. Default: released.",
                      "type": "string",
                      "enum": [
                        "released",
                        "transferred",
                        "destroyed",
                        "died"
                      ]
                    }
                  },
                  "required": [
                    "characterId",
                    "status"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "TimelineCreateEventResponse": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "event": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "timelineId": {
                "type": "string"
              },
              "when": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "until": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "at": {
                "description": "Where it sits on the timeline, for ordering: days since the calendar’s start.",
                "type": [
                  "number",
                  "null"
                ]
              },
              "trackId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "track": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "characters": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "mentioned": {
                      "type": "boolean",
                      "description": "In the event because its notes @mention them."
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "mentioned"
                  ],
                  "additionalProperties": false
                }
              },
              "scenes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "present",
                        "flashback"
                      ]
                    }
                  },
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": false
                }
              },
              "place": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "path": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "path"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "weather": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "clear",
                      "partly-cloudy",
                      "cloudy",
                      "rain",
                      "storm",
                      "tornado",
                      "flood",
                      "snow",
                      "blizzard",
                      "fog",
                      "wind"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The weather it starts in."
              },
              "weatherChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string"
                        },
                        "parts": {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "text",
                        "parts"
                      ],
                      "additionalProperties": false
                    },
                    "weather": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "clear",
                            "partly-cloudy",
                            "cloudy",
                            "rain",
                            "storm",
                            "tornado",
                            "flood",
                            "snow",
                            "blizzard",
                            "fog",
                            "wind"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "at",
                    "weather"
                  ],
                  "additionalProperties": false
                },
                "description": "Where its weather changes while it runs, in order: the moment, and the weather from then on."
              },
              "imageUrl": {
                "description": "The image across the top of its card; set it with images_set_banner.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "followsEventId": {
                "description": "The event its date is counted from, when it is.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "appearsOn": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Other timelines it shows on."
              },
              "notes": {
                "type": "string"
              },
              "statusChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "characterId": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "born",
                        "died",
                        "missing",
                        "companion_start",
                        "companion_end"
                      ]
                    },
                    "companionId": {
                      "type": "string"
                    },
                    "companionName": {
                      "type": "string"
                    },
                    "descriptor": {
                      "type": "string"
                    },
                    "why": {
                      "type": "string",
                      "enum": [
                        "released",
                        "transferred",
                        "destroyed",
                        "died"
                      ]
                    }
                  },
                  "required": [
                    "characterId",
                    "name",
                    "status"
                  ],
                  "additionalProperties": false
                },
                "description": "Who is born, dies or goes missing at it, and whose companion tie begins or ends here (characterId the character, companionId the companion), as Change Status… sets it in Dabble (kept on each character and companion link: family_get, family_set_life and family_set_companion read and set the same). Only where the plan has family trees."
              },
              "age": {
                "description": "Read with characterId: how old they are at its start, in whole years of the calendar their life is written in.",
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "title",
              "timelineId",
              "when",
              "until",
              "at",
              "trackId",
              "track",
              "characters",
              "scenes",
              "place",
              "weather",
              "weatherChanges",
              "imageUrl",
              "followsEventId",
              "appearsOn",
              "notes"
            ],
            "additionalProperties": false
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "eventId",
          "event",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineUpdateEventRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "when": {
            "description": "When it starts. Null makes it undated.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "description": "When it ends, for an event that lasts. Null makes it a moment.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "trackId": {
            "description": "The track to put it on, from timeline_get.",
            "type": "string"
          },
          "characterIds": {
            "description": "The characters in it, from character_list; replaces the list. Characters its notes @mention are in it too.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sceneIds": {
            "description": "The scenes it happens in, from dabble_get_outline; replaces the list.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sceneRoles": {
            "description": "How it is in a scene it happens in: the scene's present, or a flashback (or flash-forward) the scene looks to. Null leaves it to the dates, as Dabble does by default.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sceneId": {
                  "type": "string"
                },
                "role": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "present",
                        "flashback"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "sceneId",
                "role"
              ]
            }
          },
          "appearsOn": {
            "description": "Other timelines on the same calendar it shows on as well, from timeline_list; replaces the list. It is never copied.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "placeId": {
            "description": "The place it happens at, from location_list. Null clears it.",
            "type": [
              "string",
              "null"
            ]
          },
          "weather": {
            "description": "The weather it happens in, or starts in where it changes. Null clears it.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "clear",
                  "partly-cloudy",
                  "cloudy",
                  "rain",
                  "storm",
                  "tornado",
                  "flood",
                  "snow",
                  "blizzard",
                  "fog",
                  "wind"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "weatherChanges": {
            "description": "Where the weather changes while the event runs, replacing the list: an event that lasts (with an end) only. Null or [] clears them, leaving the one weather throughout.",
            "anyOf": [
              {
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 200
                        },
                        {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          }
                        }
                      ],
                      "description": "When the weather changes: a moment while the event runs, after its start and before its end, in its calendar (\"16 Mar 1854 15:00\")."
                    },
                    "weather": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "clear",
                            "partly-cloudy",
                            "cloudy",
                            "rain",
                            "storm",
                            "tornado",
                            "flood",
                            "snow",
                            "blizzard",
                            "fog",
                            "wind"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "The weather from then on; null where it clears to none."
                    }
                  },
                  "required": [
                    "at",
                    "weather"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "notes": {
            "description": "Its notes, replacing what is there. Plain text or light Markdown; @[Name](id) mentions a character.",
            "type": "string",
            "maxLength": 20000
          },
          "statusChanges": {
            "description": "Who is born, dies or goes missing at this event, and whose companion tie begins or ends here, written as Change Status… writes it in Dabble: on the character (or their companion link), at this event, so the family tree shows the change here. Replaces the event's list; null clears it. A status a character has at another moment moves here; a death also sets their Died date to the event's day; a companion tie that began or ended here and is left out begins before the story, or lasts, again. An event in no scene is placed in the story by its date. Needs family trees.",
            "anyOf": [
              {
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "characterId": {
                      "type": "string",
                      "description": "Character id from character_list (for a companion change: whose companion)."
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "born",
                        "died",
                        "missing",
                        "companion_start",
                        "companion_end"
                      ],
                      "description": "born, died or missing: what happens to them at this event, as Change Status… says it. companion_start or companion_end: their tie to companionId begins or ends here."
                    },
                    "companionId": {
                      "description": "For a companion change: the companion, from character_list.",
                      "type": "string"
                    },
                    "descriptor": {
                      "description": "For companion_start: what the companion is to them (\"Link AI\"); left out keeps what is there.",
                      "type": "string",
                      "maxLength": 40
                    },
                    "why": {
                      "description": "For companion_end: why it ends. Default: released.",
                      "type": "string",
                      "enum": [
                        "released",
                        "transferred",
                        "destroyed",
                        "died"
                      ]
                    }
                  },
                  "required": [
                    "characterId",
                    "status"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "TimelineUpdateEventResponse": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What changed: title, dates, track, characters, scenes, scene roles, timelines, place, weather, weather changes, notes, status changes."
          },
          "event": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "timelineId": {
                "type": "string"
              },
              "when": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "until": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "The date in its calendar’s words."
                      },
                      "parts": {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        },
                        "additionalProperties": false
                      }
                    },
                    "required": [
                      "text",
                      "parts"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "at": {
                "description": "Where it sits on the timeline, for ordering: days since the calendar’s start.",
                "type": [
                  "number",
                  "null"
                ]
              },
              "trackId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "track": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "characters": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "mentioned": {
                      "type": "boolean",
                      "description": "In the event because its notes @mention them."
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "mentioned"
                  ],
                  "additionalProperties": false
                }
              },
              "scenes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "role": {
                      "type": "string",
                      "enum": [
                        "present",
                        "flashback"
                      ]
                    }
                  },
                  "required": [
                    "id",
                    "title"
                  ],
                  "additionalProperties": false
                }
              },
              "place": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "path": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "path"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "weather": {
                "anyOf": [
                  {
                    "type": "string",
                    "enum": [
                      "clear",
                      "partly-cloudy",
                      "cloudy",
                      "rain",
                      "storm",
                      "tornado",
                      "flood",
                      "snow",
                      "blizzard",
                      "fog",
                      "wind"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The weather it starts in."
              },
              "weatherChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string"
                        },
                        "parts": {
                          "type": "object",
                          "properties": {
                            "era": {
                              "description": "Custom calendars only: the index of the era the year counts in.",
                              "type": "integer"
                            },
                            "year": {
                              "type": "integer"
                            },
                            "month": {
                              "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                              "type": "integer"
                            },
                            "day": {
                              "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                              "type": "integer"
                            },
                            "hour": {
                              "type": "integer"
                            },
                            "minute": {
                              "type": "integer"
                            }
                          },
                          "additionalProperties": false
                        }
                      },
                      "required": [
                        "text",
                        "parts"
                      ],
                      "additionalProperties": false
                    },
                    "weather": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "clear",
                            "partly-cloudy",
                            "cloudy",
                            "rain",
                            "storm",
                            "tornado",
                            "flood",
                            "snow",
                            "blizzard",
                            "fog",
                            "wind"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "at",
                    "weather"
                  ],
                  "additionalProperties": false
                },
                "description": "Where its weather changes while it runs, in order: the moment, and the weather from then on."
              },
              "imageUrl": {
                "description": "The image across the top of its card; set it with images_set_banner.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "followsEventId": {
                "description": "The event its date is counted from, when it is.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "appearsOn": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Other timelines it shows on."
              },
              "notes": {
                "type": "string"
              },
              "statusChanges": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "characterId": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "born",
                        "died",
                        "missing",
                        "companion_start",
                        "companion_end"
                      ]
                    },
                    "companionId": {
                      "type": "string"
                    },
                    "companionName": {
                      "type": "string"
                    },
                    "descriptor": {
                      "type": "string"
                    },
                    "why": {
                      "type": "string",
                      "enum": [
                        "released",
                        "transferred",
                        "destroyed",
                        "died"
                      ]
                    }
                  },
                  "required": [
                    "characterId",
                    "name",
                    "status"
                  ],
                  "additionalProperties": false
                },
                "description": "Who is born, dies or goes missing at it, and whose companion tie begins or ends here (characterId the character, companionId the companion), as Change Status… sets it in Dabble (kept on each character and companion link: family_get, family_set_life and family_set_companion read and set the same). Only where the plan has family trees."
              },
              "age": {
                "description": "Read with characterId: how old they are at its start, in whole years of the calendar their life is written in.",
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "title",
              "timelineId",
              "when",
              "until",
              "at",
              "trackId",
              "track",
              "characters",
              "scenes",
              "place",
              "weather",
              "weatherChanges",
              "imageUrl",
              "followsEventId",
              "appearsOn",
              "notes"
            ],
            "additionalProperties": false
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "eventId",
          "changed",
          "event",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineRemoveEventResponse": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "eventId",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineSetCharacterLifeRequest": {
        "type": "object",
        "properties": {
          "bornAtId": {
            "description": "The place they were born, from location_list: their dates are in the calendar it keeps (Gregorian where no place sets one), unless one is chosen. Null clears it.",
            "type": [
              "string",
              "null"
            ]
          },
          "diedAtId": {
            "description": "The place they died, from location_list. Null clears it.",
            "type": [
              "string",
              "null"
            ]
          },
          "timelineId": {
            "description": "A timeline from timeline_list: the dates are in its own calendar where nothing else says one. Where their life's calendar changes, it is what lines the old up with the new.",
            "type": "string"
          },
          "trackId": {
            "description": "A track from timeline_get: choose the calendar it keeps for their life.",
            "type": "string"
          },
          "calendarId": {
            "description": "Choose the calendar their life is in: \"gregorian\", or a calendar id from timeline_list.",
            "type": "string"
          },
          "born": {
            "description": "When they were born, in the calendar their life is written in. Null clears it.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "died": {
            "description": "When they died. Null clears it.",
            "anyOf": [
              {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A date in the calendar of the track the event is on: its words as Dabble writes them (\"16 Mar 1854 14:30\", \"Day 12\"), or its parts. Leave out the finer parts for a vaguer date: { year: 1854 } is \"sometime in 1854\"."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "TimelineSetCharacterLifeResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "born": {
            "type": [
              "string",
              "null"
            ]
          },
          "died": {
            "type": [
              "string",
              "null"
            ]
          },
          "bornAtId": {
            "type": [
              "string",
              "null"
            ]
          },
          "diedAtId": {
            "type": [
              "string",
              "null"
            ]
          },
          "calendar": {
            "description": "The calendar the dates are written in.",
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "born",
          "died",
          "bornAtId",
          "diedAtId",
          "calendar",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineSetPlaceCalendarRequest": {
        "type": "object",
        "properties": {
          "calendarId": {
            "description": "\"gregorian\", a calendar id from timeline_list, or null for the calendar of the place it is in.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "calendarId"
        ],
        "additionalProperties": false
      },
      "TimelineSetPlaceCalendarResponse": {
        "type": "object",
        "properties": {
          "placeId": {
            "type": "string"
          },
          "calendar": {
            "type": "string",
            "description": "The calendar it keeps now."
          },
          "from": {
            "description": "The place that sets it: itself, or one it is in; null for none.",
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "placeId",
          "calendar",
          "from",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineCreateCalendarRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "What the calendar is called: \"Velaran Reckoning\"."
          },
          "months": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "days": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10000
                },
                "abbreviation": {
                  "description": "How a date shortens it: \"Thw\".",
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 20
                }
              },
              "required": [
                "name",
                "days"
              ]
            },
            "description": "Its months, in the order of its year."
          },
          "eras": {
            "description": "Its eras, earliest first; none for years counted from 1 with no era.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "abbreviation": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 20,
                  "description": "What dates show after the year: \"VE\"."
                },
                "direction": {
                  "description": "Whether its years count up (the default) or down to its end, as \"BC\" does.",
                  "type": "string",
                  "enum": [
                    "forward",
                    "backward"
                  ]
                },
                "years": {
                  "description": "How many years it lasts: needed for every era but the first and the last.",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10000000
                }
              },
              "required": [
                "name",
                "abbreviation"
              ]
            }
          },
          "weekdays": {
            "description": "Its weekday names, in order.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "leap": {
            "description": "Its leap years: days a month gains, months of their own, or both.",
            "type": "object",
            "properties": {
              "every": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000,
                "description": "A leap year every this many years."
              },
              "month": {
                "description": "The month (by its number among the calendar's own) that gains the days; needed with days.",
                "type": "integer",
                "minimum": 1
              },
              "days": {
                "description": "How many days it gains. Default 0.",
                "type": "integer",
                "minimum": 0,
                "maximum": 10000
              },
              "leapMonths": {
                "description": "Whole months a leap year has besides its own: a leap period of three months every 15 years is three of them with the same after. Months are numbered 1 up in the order of the year, and a leap year's own months after them, in the order the leap rule lists them (a 12-month year's three leap months are 13, 14 and 15), wherever they stand in the year: dates, leap.month and after all use these numbers.",
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 100
                    },
                    "days": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 10000
                    },
                    "abbreviation": {
                      "description": "How a date shortens it: \"Thw\".",
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 20
                    },
                    "after": {
                      "description": "The number of the month it comes after in a leap year; 0 opens the year. Default: the end.",
                      "type": "integer",
                      "minimum": 0
                    }
                  },
                  "required": [
                    "name",
                    "days"
                  ]
                }
              },
              "except": {
                "description": "Years that would be leap and are not: every so many.",
                "type": "integer",
                "minimum": 1
              },
              "unless": {
                "description": "Years `except` skips that are leap after all.",
                "type": "integer",
                "minimum": 1
              },
              "from": {
                "description": "A year that is leap, which the count starts from.",
                "type": "integer"
              }
            },
            "required": [
              "every"
            ]
          },
          "format": {
            "type": "string",
            "maxLength": 200,
            "description": "How a date reads, in tokens: {weekday} {wkd} {day} {dd} {month} {mon} {m} {mm} {year} {era} {era_name}. Default \"{wkd}, {day} {mon}, {year} {era}\"."
          },
          "hoursPerDay": {
            "description": "Hours in its day. Default 24.",
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "minutesPerHour": {
            "description": "Minutes in its hour. Default 60.",
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "lineUp": {
            "description": "Where it stands against another calendar: one day named in both.",
            "type": "object",
            "properties": {
              "day": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "A day in the new calendar: its words, or its parts."
              },
              "sameDay": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 200
                  },
                  {
                    "type": "object",
                    "properties": {
                      "era": {
                        "description": "Custom calendars only: the index of the era the year counts in.",
                        "type": "integer"
                      },
                      "year": {
                        "type": "integer"
                      },
                      "month": {
                        "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                        "type": "integer"
                      },
                      "day": {
                        "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                        "type": "integer"
                      },
                      "hour": {
                        "type": "integer"
                      },
                      "minute": {
                        "type": "integer"
                      }
                    }
                  }
                ],
                "description": "The same day in the calendar it is lined up with."
              },
              "calendarId": {
                "type": "string",
                "description": "\"gregorian\", or a calendar id from timeline_list."
              }
            },
            "required": [
              "day",
              "sameDay",
              "calendarId"
            ]
          }
        },
        "required": [
          "name",
          "months"
        ],
        "additionalProperties": false
      },
      "TimelineCreateCalendarResponse": {
        "type": "object",
        "properties": {
          "calendarId": {
            "type": "string"
          },
          "example": {
            "type": "string",
            "description": "A date in its own words."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "calendarId",
          "example",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineGetCalendarResponse": {
        "type": "object",
        "properties": {
          "calendarId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "custom",
              "relative"
            ]
          },
          "zeroLabel": {
            "type": [
              "string",
              "null"
            ]
          },
          "months": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "number": {
                  "type": "number"
                },
                "name": {
                  "type": "string"
                },
                "abbreviation": {
                  "type": "string"
                },
                "days": {
                  "type": "number"
                }
              },
              "required": [
                "number",
                "name",
                "abbreviation",
                "days"
              ],
              "additionalProperties": false
            }
          },
          "leap": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "every": {
                    "type": "number"
                  },
                  "from": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "except": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "unless": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "month": {
                    "description": "The month that gains the leap days; null where it gains none.",
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "days": {
                    "type": "number"
                  },
                  "leapMonths": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "number": {
                          "type": "number"
                        },
                        "name": {
                          "type": "string"
                        },
                        "abbreviation": {
                          "type": "string"
                        },
                        "days": {
                          "type": "number"
                        },
                        "after": {
                          "type": "number",
                          "description": "The number of the month it follows in a leap year; 0 opens the year."
                        }
                      },
                      "required": [
                        "number",
                        "name",
                        "abbreviation",
                        "days",
                        "after"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "every",
                  "from",
                  "except",
                  "unless",
                  "month",
                  "days",
                  "leapMonths"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "yearLength": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "common": {
                    "type": "number"
                  },
                  "leap": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                },
                "required": [
                  "common",
                  "leap"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "monthOrder": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "common": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "leap": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "common",
                  "leap"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "eras": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "number"
                },
                "name": {
                  "type": "string"
                },
                "abbreviation": {
                  "type": "string"
                },
                "direction": {
                  "type": "string",
                  "enum": [
                    "forward",
                    "backward"
                  ]
                },
                "years": {
                  "type": [
                    "number",
                    "null"
                  ]
                }
              },
              "required": [
                "index",
                "name",
                "abbreviation",
                "direction",
                "years"
              ],
              "additionalProperties": false
            }
          },
          "weekdays": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "format": {
            "type": [
              "string",
              "null"
            ]
          },
          "defaultFormat": {
            "type": [
              "string",
              "null"
            ]
          },
          "hoursPerDay": {
            "type": "number"
          },
          "minutesPerHour": {
            "type": "number"
          },
          "lineUp": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "day": {
                    "type": "string",
                    "description": "A day in this calendar, in its words."
                  },
                  "sameDay": {
                    "type": "string",
                    "description": "The same day in the other calendar, in its words."
                  },
                  "calendarId": {
                    "type": "string",
                    "description": "\"gregorian\", or the other calendar’s id."
                  },
                  "calendar": {
                    "type": "string",
                    "description": "The other calendar’s name."
                  }
                },
                "required": [
                  "day",
                  "sameDay",
                  "calendarId",
                  "calendar"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "example": {
            "type": "string"
          },
          "inUse": {
            "type": "object",
            "properties": {
              "dates": {
                "type": "number",
                "description": "Dates written in it: events, tracks’ and books’ days, line-ups, lives."
              },
              "months": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "The months they are in, by number."
              },
              "eras": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "description": "The eras they are in, by index."
              }
            },
            "required": [
              "dates",
              "months",
              "eras"
            ],
            "additionalProperties": false
          },
          "years": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "from": {
                    "type": "number"
                  },
                  "to": {
                    "type": "number"
                  },
                  "era": {
                    "type": "number"
                  },
                  "leapYears": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "list": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "year": {
                              "type": "number"
                            },
                            "label": {
                              "type": "string"
                            },
                            "days": {
                              "type": "number"
                            },
                            "leap": {
                              "type": "boolean"
                            }
                          },
                          "required": [
                            "year",
                            "label",
                            "days",
                            "leap"
                          ],
                          "additionalProperties": false
                        }
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Each year, for a span of up to 100."
                  }
                },
                "required": [
                  "from",
                  "to",
                  "era",
                  "leapYears",
                  "list"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "calendarId",
          "name",
          "kind",
          "zeroLabel",
          "months",
          "leap",
          "yearLength",
          "monthOrder",
          "eras",
          "weekdays",
          "format",
          "defaultFormat",
          "hoursPerDay",
          "minutesPerHour",
          "lineUp",
          "example",
          "inUse",
          "years"
        ],
        "additionalProperties": false
      },
      "TimelineUpdateCalendarRequest": {
        "type": "object",
        "properties": {
          "name": {
            "description": "What it is called now.",
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "lineUp": {
            "description": "Where it stands against another calendar: one day named in both. Null for none.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "day": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        }
                      }
                    ],
                    "description": "A day in this calendar: its words, or its parts."
                  },
                  "sameDay": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 200
                      },
                      {
                        "type": "object",
                        "properties": {
                          "era": {
                            "description": "Custom calendars only: the index of the era the year counts in.",
                            "type": "integer"
                          },
                          "year": {
                            "type": "integer"
                          },
                          "month": {
                            "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                            "type": "integer"
                          },
                          "day": {
                            "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                            "type": "integer"
                          },
                          "hour": {
                            "type": "integer"
                          },
                          "minute": {
                            "type": "integer"
                          }
                        }
                      }
                    ],
                    "description": "The same day in the calendar it is lined up with."
                  },
                  "calendarId": {
                    "type": "string",
                    "description": "\"gregorian\", or a calendar id from timeline_list."
                  }
                },
                "required": [
                  "day",
                  "sameDay",
                  "calendarId"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "months": {
            "description": "All its months, in the order of its year: replaces them.",
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "days": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10000
                },
                "abbreviation": {
                  "description": "How a date shortens it: \"Thw\".",
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 20
                },
                "was": {
                  "description": "The number it has now (timeline_get_calendar), so the dates in it stay in it: renamed, resized or moved. Leave out for a new month.",
                  "type": "integer",
                  "minimum": 1
                }
              },
              "required": [
                "name",
                "days"
              ]
            }
          },
          "leap": {
            "description": "Its leap rule and leap months, whole: replaces them. Null for no leap years.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "every": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000,
                    "description": "A leap year every this many years."
                  },
                  "month": {
                    "description": "The month (by its number among the calendar's own) that gains the days; needed with days.",
                    "type": "integer",
                    "minimum": 1
                  },
                  "days": {
                    "description": "How many days it gains. Default 0.",
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 10000
                  },
                  "leapMonths": {
                    "description": "Whole months a leap year has besides its own: a leap period of three months every 15 years is three of them with the same after. Months are numbered 1 up in the order of the year, and a leap year's own months after them, in the order the leap rule lists them (a 12-month year's three leap months are 13, 14 and 15), wherever they stand in the year: dates, leap.month and after all use these numbers.",
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        },
                        "days": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 10000
                        },
                        "abbreviation": {
                          "description": "How a date shortens it: \"Thw\".",
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 20
                        },
                        "was": {
                          "description": "The number it has now (timeline_get_calendar), so the dates in it stay in it: renamed, resized or moved. Leave out for a new month.",
                          "type": "integer",
                          "minimum": 1
                        },
                        "after": {
                          "description": "The number of the month it comes after in a leap year; 0 opens the year. Default: the end.",
                          "type": "integer",
                          "minimum": 0
                        }
                      },
                      "required": [
                        "name",
                        "days"
                      ]
                    }
                  },
                  "except": {
                    "description": "Years that would be leap and are not: every so many.",
                    "type": "integer",
                    "minimum": 1
                  },
                  "unless": {
                    "description": "Years `except` skips that are leap after all.",
                    "type": "integer",
                    "minimum": 1
                  },
                  "from": {
                    "description": "A year that is leap, which the count starts from.",
                    "type": "integer"
                  }
                },
                "required": [
                  "every"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "eras": {
            "description": "All its eras, earliest first: replaces them. None for years counted from 1 with no era.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "abbreviation": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 20,
                  "description": "What dates show after the year: \"VE\"."
                },
                "direction": {
                  "description": "Whether its years count up (the default) or down to its end, as \"BC\" does.",
                  "type": "string",
                  "enum": [
                    "forward",
                    "backward"
                  ]
                },
                "years": {
                  "description": "How many years it lasts: needed for every era but the first and the last.",
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 10000000
                },
                "was": {
                  "description": "The index it has now (0 the earliest), so the dates in it stay in it. Leave out for a new era.",
                  "type": "integer",
                  "minimum": 0
                }
              },
              "required": [
                "name",
                "abbreviation"
              ]
            }
          },
          "weekdays": {
            "description": "Its weekday names; none for no week.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "format": {
            "description": "How a date reads; null for the default.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200,
                "description": "How a date reads, in tokens: {weekday} {wkd} {day} {dd} {month} {mon} {m} {mm} {year} {era} {era_name}. Default \"{wkd}, {day} {mon}, {year} {era}\"."
              },
              {
                "type": "null"
              }
            ]
          },
          "hoursPerDay": {
            "description": "Hours in its day; null for 24.",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "minutesPerHour": {
            "description": "Minutes in its hour; null for 60.",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "shiftDates": {
            "description": "With a new line-up or structure: \"keep\" (default) leaves the dates written in it in their words; \"move\" rewrites them to stay at their moment.",
            "type": "string",
            "enum": [
              "keep",
              "move"
            ]
          },
          "dryRun": {
            "description": "Say what would change, and change nothing.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TimelineUpdateCalendarResponse": {
        "type": "object",
        "properties": {
          "calendarId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "dryRun": {
            "type": "boolean"
          },
          "before": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "day": {
                    "type": "string",
                    "description": "A day in this calendar, in its words."
                  },
                  "sameDay": {
                    "type": "string",
                    "description": "The same day in the other calendar, in its words."
                  },
                  "calendarId": {
                    "type": "string",
                    "description": "\"gregorian\", or the other calendar’s id."
                  },
                  "calendar": {
                    "type": "string",
                    "description": "The other calendar’s name."
                  }
                },
                "required": [
                  "day",
                  "sameDay",
                  "calendarId",
                  "calendar"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "after": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "day": {
                    "type": "string",
                    "description": "A day in this calendar, in its words."
                  },
                  "sameDay": {
                    "type": "string",
                    "description": "The same day in the other calendar, in its words."
                  },
                  "calendarId": {
                    "type": "string",
                    "description": "\"gregorian\", or the other calendar’s id."
                  },
                  "calendar": {
                    "type": "string",
                    "description": "The other calendar’s name."
                  }
                },
                "required": [
                  "day",
                  "sameDay",
                  "calendarId",
                  "calendar"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "shiftDates": {
            "type": "string",
            "enum": [
              "keep",
              "move"
            ]
          },
          "shiftedBy": {
            "type": "number",
            "description": "With a line-up: how many of its days its dates moved by, whole: 0 unless \"move\"."
          },
          "structure": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The parts of its structure that change: months, leap, eras, weekdays, format, clock."
          },
          "events": {
            "type": "number",
            "description": "Live events dated in it."
          },
          "keptBy": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The timelines and tracks that keep it."
          },
          "lives": {
            "type": "object",
            "properties": {
              "inCalendar": {
                "type": "number",
                "description": "Characters whose lives are written in it."
              },
              "elsewhere": {
                "type": "number",
                "description": "With \"keep\" and a line-up: characters with lives in a calendar lined up with it, aged again against its dates."
              },
              "noCalendar": {
                "type": "number",
                "description": "Lives kept in no calendar of their own, read in its words on its timelines: left as they are."
              }
            },
            "required": [
              "inCalendar",
              "elsewhere",
              "noCalendar"
            ],
            "additionalProperties": false
          },
          "trashed": {
            "type": "number",
            "description": "Events in the trash that kept their words: restored, they read as left."
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "event",
                    "track",
                    "book",
                    "calendar",
                    "life"
                  ]
                },
                "id": {
                  "type": "string",
                  "description": "The event, track, timeline (for a book's window), calendar or character."
                },
                "title": {
                  "type": "string"
                },
                "field": {
                  "type": "string",
                  "description": "Which of its dates: when, until, day, start, end, lineUp, born or died."
                },
                "before": {
                  "type": "string"
                },
                "after": {
                  "type": "string"
                },
                "movedDays": {
                  "description": "How far it moves against the calendar it is lined up with (its own start where there is none), in days; 0 where it holds its moment, null where there was nothing to hold it to.",
                  "type": [
                    "number",
                    "null"
                  ]
                }
              },
              "required": [
                "kind",
                "id",
                "title",
                "field",
                "before",
                "after",
                "movedDays"
              ],
              "additionalProperties": false
            },
            "description": "The dates whose words or moment change, up to 50."
          },
          "changed": {
            "type": "object",
            "properties": {
              "dates": {
                "type": "number",
                "description": "Dates written in it, lives’ included."
              },
              "reworded": {
                "type": "number",
                "description": "Of those, the dates whose words change."
              },
              "moved": {
                "type": "number",
                "description": "Of those, the dates that move against the calendar it is lined up with."
              }
            },
            "required": [
              "dates",
              "reworded",
              "moved"
            ],
            "additionalProperties": false
          },
          "sample": {
            "description": "One of its dates, as it reads now.",
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "calendarId",
          "name",
          "dryRun",
          "before",
          "after",
          "shiftDates",
          "shiftedBy",
          "structure",
          "events",
          "keptBy",
          "lives",
          "trashed",
          "changes",
          "changed",
          "sample",
          "rev"
        ],
        "additionalProperties": false
      },
      "TimelineConvertDateRequest": {
        "type": "object",
        "properties": {
          "date": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "object",
                "properties": {
                  "era": {
                    "description": "Custom calendars only: the index of the era the year counts in.",
                    "type": "integer"
                  },
                  "year": {
                    "type": "integer"
                  },
                  "month": {
                    "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                    "type": "integer"
                  },
                  "day": {
                    "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                    "type": "integer"
                  },
                  "hour": {
                    "type": "integer"
                  },
                  "minute": {
                    "type": "integer"
                  }
                }
              }
            ],
            "description": "A date in the calendar it is from: its words, or its parts."
          },
          "fromCalendarId": {
            "type": "string",
            "description": "\"gregorian\", or a calendar id from timeline_list."
          },
          "toCalendarId": {
            "type": "string",
            "description": "\"gregorian\", or a calendar id from timeline_list."
          }
        },
        "required": [
          "date",
          "fromCalendarId",
          "toCalendarId"
        ],
        "additionalProperties": false
      },
      "TimelineConvertDateResponse": {
        "type": "object",
        "properties": {
          "from": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string"
              },
              "parts": {
                "type": "object",
                "properties": {
                  "era": {
                    "description": "Custom calendars only: the index of the era the year counts in.",
                    "type": "integer"
                  },
                  "year": {
                    "type": "integer"
                  },
                  "month": {
                    "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                    "type": "integer"
                  },
                  "day": {
                    "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                    "type": "integer"
                  },
                  "hour": {
                    "type": "integer"
                  },
                  "minute": {
                    "type": "integer"
                  }
                },
                "additionalProperties": false
              }
            },
            "required": [
              "text",
              "parts"
            ],
            "additionalProperties": false
          },
          "to": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string"
              },
              "parts": {
                "type": "object",
                "properties": {
                  "era": {
                    "description": "Custom calendars only: the index of the era the year counts in.",
                    "type": "integer"
                  },
                  "year": {
                    "type": "integer"
                  },
                  "month": {
                    "description": "1-based. A custom calendar's leap months are numbered after its own months, wherever they fall.",
                    "type": "integer"
                  },
                  "day": {
                    "description": "Day of the month; on a relative calendar, the day number (Day 0 = 0).",
                    "type": "integer"
                  },
                  "hour": {
                    "type": "integer"
                  },
                  "minute": {
                    "type": "integer"
                  }
                },
                "additionalProperties": false
              }
            },
            "required": [
              "text",
              "parts"
            ],
            "additionalProperties": false
          },
          "through": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The calendars between the two that line them up, if any."
          }
        },
        "required": [
          "from",
          "to",
          "through"
        ],
        "additionalProperties": false
      },
      "TimelineRemoveCalendarResponse": {
        "type": "object",
        "properties": {
          "calendarId": {
            "type": "string"
          },
          "usedBy": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The timelines and tracks that kept it, which now read as Gregorian."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "calendarId",
          "usedBy",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterListResponse": {
        "type": "object",
        "properties": {
          "casts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "cast": {
                  "type": "string",
                  "description": "Cast title."
                },
                "castId": {
                  "type": "string"
                },
                "characters": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "summary": {
                        "type": "string"
                      },
                      "hasAvatar": {
                        "type": "boolean",
                        "description": "Whether the character has a portrait."
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "summary",
                      "hasAvatar"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "cast",
                "castId",
                "characters"
              ],
              "additionalProperties": false
            }
          },
          "total": {
            "type": "number"
          }
        },
        "required": [
          "casts",
          "total"
        ],
        "additionalProperties": false
      },
      "CharacterGetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "castId": {
            "type": "string"
          },
          "avatarUrl": {
            "description": "The character's portrait, when it has one.",
            "type": "string"
          },
          "bannerUrl": {
            "description": "The banner image above the character's page, when it has one.",
            "type": "string"
          },
          "sheet": {
            "type": "object",
            "properties": {
              "sections": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "heading": {
                      "description": "Section heading, or null for terms before the first heading.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "terms": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "term": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "term",
                          "value"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "heading",
                    "terms"
                  ],
                  "additionalProperties": false
                }
              },
              "intro": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Paragraphs before the first term list, in order."
              },
              "prose": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The other paragraphs that are not part of any term list, in order."
              }
            },
            "required": [
              "sections",
              "intro",
              "prose"
            ],
            "additionalProperties": false
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "content": {
                  "type": "string",
                  "description": "The card text as plain text."
                },
                "labels": {
                  "description": "The texts of the labels on the card, when it has any.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "title",
                "content"
              ],
              "additionalProperties": false
            }
          },
          "pages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "folder",
                    "page"
                  ]
                },
                "words": {
                  "type": "number"
                }
              },
              "required": [
                "id",
                "title",
                "kind"
              ],
              "additionalProperties": false
            }
          },
          "povScenes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title"
              ],
              "additionalProperties": false
            },
            "description": "Scenes written from their point of view."
          },
          "addedToScenes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title"
              ],
              "additionalProperties": false
            },
            "description": "Scenes the author added them to by hand (besides those that name them)."
          }
        },
        "required": [
          "id",
          "name",
          "sheet",
          "notes",
          "pages",
          "povScenes",
          "addedToScenes"
        ],
        "additionalProperties": false
      },
      "CharacterGetSceneCastResponse": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string"
          },
          "pov": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "added": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "sceneId",
          "pov",
          "added"
        ],
        "additionalProperties": false
      },
      "CharacterSetPovRequest": {
        "type": "object",
        "properties": {
          "characterId": {
            "description": "Character id from character_list, or null for none.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "characterId"
        ],
        "additionalProperties": false
      },
      "CharacterSetPovResponse": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string"
          },
          "characterId": {
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "sceneId",
          "characterId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterAddToSceneResponse": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string"
          },
          "characterId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "sceneId",
          "characterId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterRemoveFromSceneResponse": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string"
          },
          "characterId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "sceneId",
          "characterId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterCreateRequest": {
        "type": "object",
        "properties": {
          "parentId": {
            "description": "Where it goes: the Characters section (\"characters\"), a cast, or another group that holds characters, such as a family tree or a hierarchy (ids from character_list). Default: the Characters section.",
            "type": "string",
            "minLength": 1
          },
          "castId": {
            "description": "Deprecated: use parentId, which takes the same ids.",
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "subtitle": {
            "description": "Role or tagline shown under the name.",
            "type": "string",
            "maxLength": 300
          },
          "excerpt": {
            "description": "A short description shown on the card.",
            "type": "string",
            "maxLength": 2000
          },
          "sheet": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "heading": {
                  "type": "string",
                  "maxLength": 300
                },
                "terms": {
                  "maxItems": 50,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "term": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "value": {
                        "type": "string",
                        "maxLength": 5000
                      }
                    },
                    "required": [
                      "term",
                      "value"
                    ]
                  }
                }
              },
              "required": [
                "terms"
              ]
            }
          },
          "notes": {
            "description": "Free-form text after the sheet. Plain text or light Markdown.",
            "type": "string",
            "maxLength": 20000
          },
          "templateIds": {
            "description": "Templates to build the sheet from, in order (ids from character_list_templates), as the author's template picker does. The sheet's values then fill in the templates' terms; a term the templates do not have is added.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "language": {
            "description": "The language the author writes their sheets in, as a code (en, de, fr, es, ...). Default en. Dabble translates a template into the author's language when they insert it, so match the language of their existing sheets.",
            "type": "string",
            "enum": [
              "en",
              "ca",
              "cs",
              "da",
              "de",
              "el",
              "es",
              "fi",
              "fr",
              "hr",
              "it",
              "lb",
              "nb",
              "nl",
              "nn",
              "pl",
              "pt",
              "ro",
              "sr",
              "sv",
              "uk"
            ]
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "CharacterCreateResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "parentId": {
            "type": "string",
            "description": "Where the character was created."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "parentId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 300
          },
          "updateReferences": {
            "description": "On a rename, also replace the old name across the project (scenes, notes, summaries and titles), as Dabble's rename prompt would, and save the rename as a named version. Default true; pass false to rename only.",
            "type": "boolean"
          },
          "subtitle": {
            "description": "Role or tagline shown under the name.",
            "type": "string",
            "maxLength": 300
          },
          "excerpt": {
            "description": "A short description shown on the card.",
            "type": "string",
            "maxLength": 2000
          },
          "notes": {
            "description": "Free-form text after the sheet. Replaces what is there unless append is true.",
            "type": "string",
            "maxLength": 20000
          },
          "append": {
            "description": "Add the notes text after the existing text instead of replacing it.",
            "type": "boolean"
          },
          "intro": {
            "description": "Free-form text before the sheet, replacing what is there. Empty removes it, as when its content has moved into the sheet.",
            "type": "string",
            "maxLength": 20000
          },
          "replace": {
            "type": "object",
            "properties": {
              "find": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The passage to replace, quoted as the text reads. It may run across paragraphs, bullets and headings when quoted as the markdown read shows it (`## Heading`, `- bullet`, blocks apart by a blank line); spacing and line breaks need not match exactly."
              },
              "with": {
                "type": "string",
                "maxLength": 20000,
                "description": "The replacement, in plain text or light Markdown. Empty removes the passage, and a paragraph, bullet or heading left with no text is removed with it."
              },
              "occurrence": {
                "description": "Which occurrence (1-based) when the passage repeats.",
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "find",
              "with"
            ]
          },
          "removeSections": {
            "description": "Headings of sections to remove, each with everything under it up to the next heading of the same or a higher level, the next line in bold, or the property list. A heading is a #-heading of any level or a line in bold (**Appearance**); case, spacing and a trailing colon do not matter. Returns what went and saves a named version.",
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          },
          "includeSheet": {
            "description": "Let removeSections remove a property-list (sheet) heading, with all its terms and values. Without it a sheet heading is refused, so a stray call cannot wipe a template.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CharacterUpdateResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What changed: name, subtitle, excerpt, text, text before the sheet, a passage, or sections."
          },
          "removed": {
            "description": "What the call removed, when it took out whole blocks.",
            "type": "object",
            "properties": {
              "blocks": {
                "type": "number",
                "description": "Paragraphs, bullets and headings taken out whole."
              },
              "headings": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The headings among them."
              },
              "paragraphs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The opening words of every other block that went."
              },
              "images": {
                "type": "number",
                "description": "Images that went with them."
              }
            },
            "required": [
              "blocks",
              "headings",
              "paragraphs",
              "images"
            ],
            "additionalProperties": false
          },
          "sections": {
            "description": "The sections removeSections took off, as their headings read.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "keptSheet": {
            "description": "Names that also head a property list, which was left alone (pass includeSheet to remove it too).",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "version": {
            "description": "After a rename: the named version it was saved as in version history.",
            "type": "string"
          },
          "namesReplaced": {
            "description": "After a rename: how many times the old name was replaced across the project, scenes included.",
            "type": "number"
          },
          "oldNameUses": {
            "description": "After a rename: where the old name is still written as plain text, no longer linked (a name another linked document also goes by is left for the author).",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "uses": {
                  "type": "number"
                },
                "documents": {
                  "type": "number"
                },
                "manuscript": {
                  "type": "number",
                  "description": "How many of those documents are in the manuscript, which Connect cannot edit."
                }
              },
              "required": [
                "name",
                "uses",
                "documents",
                "manuscript"
              ],
              "additionalProperties": false
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterSetTermsRequest": {
        "type": "object",
        "properties": {
          "terms": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "heading": {
                  "description": "Section heading, e.g. \"Appearance\".",
                  "type": "string",
                  "maxLength": 300
                },
                "term": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "value": {
                  "type": "string",
                  "maxLength": 5000
                }
              },
              "required": [
                "term",
                "value"
              ]
            }
          }
        },
        "required": [
          "terms"
        ],
        "additionalProperties": false
      },
      "CharacterSetTermsResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "updated": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Terms whose value was replaced."
          },
          "added": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Terms added to the sheet."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "updated",
          "added",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterListTemplatesResponse": {
        "type": "object",
        "properties": {
          "templates": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Template id, the same in every language."
                },
                "name": {
                  "type": "string",
                  "description": "The heading the template puts on a sheet."
                },
                "terms": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "The terms it starts with, in order. Every one starts empty."
                },
                "builtIn": {
                  "type": "boolean",
                  "const": true,
                  "description": "Built into Dabble: authors cannot make their own templates yet."
                }
              },
              "required": [
                "id",
                "name",
                "terms",
                "builtIn"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "templates"
        ],
        "additionalProperties": false
      },
      "CharacterGetTemplateResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Template id, the same in every language."
          },
          "name": {
            "type": "string",
            "description": "The heading the template puts on a sheet."
          },
          "terms": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The terms it starts with, in order. Every one starts empty."
          },
          "builtIn": {
            "type": "boolean",
            "const": true,
            "description": "Built into Dabble: authors cannot make their own templates yet."
          }
        },
        "required": [
          "id",
          "name",
          "terms",
          "builtIn"
        ],
        "additionalProperties": false
      },
      "CharacterApplyTemplateRequest": {
        "type": "object",
        "properties": {
          "templateId": {
            "type": "string",
            "minLength": 1,
            "description": "Template id from character_list_templates, or its name."
          },
          "mode": {
            "description": "merge (default), missing, or replace.",
            "type": "string",
            "enum": [
              "merge",
              "missing",
              "replace"
            ]
          },
          "language": {
            "description": "The language the author writes their sheets in, as a code (en, de, fr, es, ...). Default en. Dabble translates a template into the author's language when they insert it, so match the language of their existing sheets.",
            "type": "string",
            "enum": [
              "en",
              "ca",
              "cs",
              "da",
              "de",
              "el",
              "es",
              "fi",
              "fr",
              "hr",
              "it",
              "lb",
              "nb",
              "nl",
              "nn",
              "pl",
              "pt",
              "ro",
              "sr",
              "sv",
              "uk"
            ]
          }
        },
        "required": [
          "templateId"
        ],
        "additionalProperties": false
      },
      "CharacterApplyTemplateResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "templateId": {
            "type": "string"
          },
          "added": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Headings and terms added, as \"Heading\" or \"Heading: Term\"."
          },
          "moved": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Terms that changed heading, as \"Term → Heading\"."
          },
          "unfilled": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The template's terms with no value yet, as \"Heading: Term\"."
          },
          "removedHeadings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Headings replace took off the sheet; their term rows are under Not in Template. A heading with only text under it is never removed."
          },
          "version": {
            "description": "The version the change was saved as.",
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "templateId",
          "added",
          "moved",
          "unfilled",
          "removedHeadings",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterCreateCastRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "What the cast is called."
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "CharacterCreateCastResponse": {
        "type": "object",
        "properties": {
          "castId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "castId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterRemoveResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CharacterRemoveCastResponse": {
        "type": "object",
        "properties": {
          "castId": {
            "type": "string"
          },
          "charactersTrashed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the characters that went with it."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "castId",
          "charactersTrashed",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilyGetResponse": {
        "type": "object",
        "properties": {
          "character": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "enum": [
                  "unborn",
                  "alive",
                  "dead",
                  "missing"
                ],
                "description": "As of the moment: not yet born, alive, dead or missing."
              },
              "born": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "ref": {
                        "type": "string",
                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                      },
                      "label": {
                        "type": "string",
                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                      },
                      "placed": {
                        "type": "boolean",
                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                      }
                    },
                    "required": [
                      "ref",
                      "label",
                      "placed"
                    ],
                    "additionalProperties": false,
                    "description": "A moment of the story."
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "When they are born in the story; null: alive from before it."
              },
              "died": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "ref": {
                        "type": "string",
                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                      },
                      "label": {
                        "type": "string",
                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                      },
                      "placed": {
                        "type": "boolean",
                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                      }
                    },
                    "required": [
                      "ref",
                      "label",
                      "placed"
                    ],
                    "additionalProperties": false,
                    "description": "A moment of the story."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "missing": {
                "anyOf": [
                  {
                    "type": "object",
                    "properties": {
                      "ref": {
                        "type": "string",
                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                      },
                      "label": {
                        "type": "string",
                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                      },
                      "placed": {
                        "type": "boolean",
                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                      }
                    },
                    "required": [
                      "ref",
                      "label",
                      "placed"
                    ],
                    "additionalProperties": false,
                    "description": "A moment of the story."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "widowed": {
                "type": "boolean"
              }
            },
            "required": [
              "id",
              "name",
              "status",
              "born",
              "died",
              "missing",
              "widowed"
            ],
            "additionalProperties": false
          },
          "asOf": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ],
            "description": "The moment it is read as of; null for the latest."
          },
          "parents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "birth",
                    "adoptive",
                    "step",
                    "foster",
                    "guardian"
                  ]
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they became the parent (an adoption, a remarriage); null: from the start."
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When it stopped (a fostering ending); a death is worked out, never kept."
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "kind",
                "tie",
                "from",
                "until"
              ],
              "additionalProperties": false
            }
          },
          "partners": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "married",
                    "partners",
                    "betrothed"
                  ]
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "ending": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "died",
                            "divorced",
                            "separated"
                          ]
                        },
                        "workedOut": {
                          "type": "boolean",
                          "description": "Ended by a death, worked out rather than kept on the tie."
                        }
                      },
                      "required": [
                        "moment",
                        "why",
                        "workedOut"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "kind",
                "tie",
                "from",
                "ending"
              ],
              "additionalProperties": false
            }
          },
          "children": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "birth",
                    "adoptive",
                    "step",
                    "foster",
                    "guardian"
                  ]
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they became the parent (an adoption, a remarriage); null: from the start."
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When it stopped (a fostering ending); a death is worked out, never kept."
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "kind",
                "tie",
                "from",
                "until"
              ],
              "additionalProperties": false
            }
          },
          "siblings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "half": {
                  "type": "boolean"
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "saidOutright": {
                  "type": "boolean",
                  "description": "A sibling tie of its own, rather than worked out from shared parents."
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "half",
                "tie",
                "saidOutright"
              ],
              "additionalProperties": false
            }
          },
          "companions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "descriptor": {
                  "description": "What the companion is to them, shown on the tree: \"Link AI\".",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "released",
                            "transferred",
                            "destroyed",
                            "died"
                          ]
                        }
                      },
                      "required": [
                        "moment",
                        "why"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When and why the tie ended, as the author set it; null: it lasts (no death ends it by itself)."
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "descriptor",
                "tie",
                "from",
                "until"
              ],
              "additionalProperties": false
            },
            "description": "Their companions: outside the bloodline, never kin."
          },
          "companionOf": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "descriptor": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "tie": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "released",
                            "transferred",
                            "destroyed",
                            "died"
                          ]
                        }
                      },
                      "required": [
                        "moment",
                        "why"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When and why the tie ended, as the author set it; null: it lasts (no death ends it by itself)."
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "descriptor",
                "tie",
                "from",
                "until"
              ],
              "additionalProperties": false
            },
            "description": "The characters they are a companion of."
          },
          "grandparents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                },
                "throughParentId": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "birth",
                    "adoptive",
                    "step",
                    "foster",
                    "guardian"
                  ]
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed",
                "throughParentId",
                "kind"
              ],
              "additionalProperties": false
            }
          },
          "trees": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title"
              ],
              "additionalProperties": false
            },
            "description": "The family trees they are on."
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string",
                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                },
                "label": {
                  "type": "string",
                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                },
                "placed": {
                  "type": "boolean",
                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                }
              },
              "required": [
                "ref",
                "label",
                "placed"
              ],
              "additionalProperties": false,
              "description": "A moment of the story."
            },
            "description": "The moments their family changes, in Reading Order."
          },
          "statusChanges": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "characterId": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "born",
                    "died",
                    "missing"
                  ]
                },
                "event": {
                  "type": "object",
                  "properties": {
                    "ref": {
                      "type": "string",
                      "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                    },
                    "label": {
                      "type": "string",
                      "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                    },
                    "placed": {
                      "type": "boolean",
                      "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                    }
                  },
                  "required": [
                    "ref",
                    "label",
                    "placed"
                  ],
                  "additionalProperties": false,
                  "description": "A moment of the story."
                }
              },
              "required": [
                "characterId",
                "name",
                "status",
                "event"
              ],
              "additionalProperties": false
            },
            "description": "Who here (them and the family read) is born, dies or goes missing at a timeline event, and at which: the status changes timeline_update_event sets."
          }
        },
        "required": [
          "character",
          "asOf",
          "parents",
          "partners",
          "children",
          "siblings",
          "companions",
          "companionOf",
          "grandparents",
          "trees",
          "changes",
          "statusChanges"
        ],
        "additionalProperties": false
      },
      "FamilySetParentRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "description": "Default: birth, or what it was.",
            "type": "string",
            "enum": [
              "birth",
              "adoptive",
              "step",
              "foster",
              "guardian"
            ]
          },
          "from": {
            "description": "When they became the parent; null: from the start.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "description": "When it stopped; null: never.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "FamilySetParentResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "boolean"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "created",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilySetPartnerRequest": {
        "type": "object",
        "properties": {
          "kind": {
            "description": "Default: married, or what it was.",
            "type": "string",
            "enum": [
              "married",
              "partners",
              "betrothed"
            ]
          },
          "from": {
            "description": "When they married or got together; null: before the story.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "description": "When and why it ended, other than by a death Dabble knows of; null: it lasts.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "moment": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                  },
                  "why": {
                    "type": "string",
                    "enum": [
                      "divorced",
                      "separated",
                      "died"
                    ]
                  }
                },
                "required": [
                  "moment",
                  "why"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "FamilySetPartnerResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "boolean"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "created",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilySetSiblingRequest": {
        "type": "object",
        "properties": {
          "half": {
            "description": "Half-siblings: they share one parent the project does not hold.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "FamilySetSiblingResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "boolean"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "created",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilySetCompanionRequest": {
        "type": "object",
        "properties": {
          "descriptor": {
            "description": "What the companion is to them: \"Link AI\", \"familiar\". null clears it (shown as Companion).",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          },
          "from": {
            "description": "When it began; null: before the story.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "description": "When and why it ended: released, transferred, destroyed or died; null: it lasts.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "moment": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                  },
                  "why": {
                    "type": "string",
                    "enum": [
                      "released",
                      "transferred",
                      "destroyed",
                      "died"
                    ]
                  }
                },
                "required": [
                  "moment",
                  "why"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "replaceExisting": {
            "description": "Take away a partner or sibling tie between the two, in the same change.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "FamilySetCompanionResponse": {
        "type": "object",
        "properties": {
          "created": {
            "type": "boolean"
          },
          "replaced": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "created",
          "replaced",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilyUnlinkResponse": {
        "type": "object",
        "properties": {
          "removed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "removed",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilySetLifeRequest": {
        "type": "object",
        "properties": {
          "born": {
            "description": "Born in the story at this moment; null: alive from before it.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "died": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "missing": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "FamilySetLifeResponse": {
        "type": "object",
        "properties": {
          "born": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "died": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "missing": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "born",
          "died",
          "missing",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilyTreeListResponse": {
        "type": "object",
        "properties": {
          "trees": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "root": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The character it grows from."
                },
                "depth": {
                  "description": "How many steps of kinship it reaches; null for all of the family.",
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "members": {
                  "type": "number",
                  "description": "How many characters it shows."
                }
              },
              "required": [
                "id",
                "title",
                "root",
                "depth",
                "members"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "trees"
        ],
        "additionalProperties": false
      },
      "FamilyTreeGetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "root": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The character it grows from."
          },
          "depth": {
            "description": "How many steps of kinship it reaches; null for all of the family.",
            "type": [
              "number",
              "null"
            ]
          },
          "members": {
            "type": "number",
            "description": "How many characters it shows."
          },
          "asOf": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "people": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "unborn",
                    "alive",
                    "dead",
                    "missing"
                  ],
                  "description": "As of the moment: not yet born, alive, dead or missing."
                },
                "born": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they are born in the story; null: alive from before it."
                },
                "died": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "missing": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "widowed": {
                  "type": "boolean"
                }
              },
              "required": [
                "id",
                "name",
                "status",
                "born",
                "died",
                "missing",
                "widowed"
              ],
              "additionalProperties": false
            }
          },
          "parents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "childId": {
                  "type": "string"
                },
                "parentId": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "birth",
                    "adoptive",
                    "step",
                    "foster",
                    "guardian"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "childId",
                "parentId",
                "kind",
                "status",
                "from",
                "until"
              ],
              "additionalProperties": false
            }
          },
          "partners": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "aId": {
                  "type": "string"
                },
                "bId": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "married",
                    "partners",
                    "betrothed"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "ending": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "died",
                            "divorced",
                            "separated"
                          ]
                        }
                      },
                      "required": [
                        "moment",
                        "why"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "aId",
                "bId",
                "kind",
                "status",
                "from",
                "ending"
              ],
              "additionalProperties": false
            }
          },
          "siblings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "aId": {
                  "type": "string"
                },
                "bId": {
                  "type": "string"
                },
                "half": {
                  "type": "boolean"
                }
              },
              "required": [
                "aId",
                "bId",
                "half"
              ],
              "additionalProperties": false
            },
            "description": "Siblings said outright; those who share parents are read from the parents."
          },
          "companions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "characterId": {
                  "type": "string",
                  "description": "Whose companion it is."
                },
                "companionId": {
                  "type": "string"
                },
                "descriptor": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "released",
                            "transferred",
                            "destroyed",
                            "died"
                          ]
                        }
                      },
                      "required": [
                        "moment",
                        "why"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When and why the tie ended, as the author set it; null: it lasts (no death ends it by itself)."
                }
              },
              "required": [
                "characterId",
                "companionId",
                "descriptor",
                "status",
                "from",
                "until"
              ],
              "additionalProperties": false
            }
          },
          "showCompanions": {
            "type": "boolean",
            "description": "Whether the tree shows companions; false is a pure bloodline view."
          },
          "standalone": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "Companions placed on the tree by themselves, whether or not their characters are on it."
          },
          "hidden": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "Characters folded away from it."
          },
          "opened": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "Partners who married in, whose own families it shows."
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string",
                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                },
                "label": {
                  "type": "string",
                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                },
                "placed": {
                  "type": "boolean",
                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                }
              },
              "required": [
                "ref",
                "label",
                "placed"
              ],
              "additionalProperties": false,
              "description": "A moment of the story."
            }
          }
        },
        "required": [
          "id",
          "title",
          "root",
          "depth",
          "members",
          "asOf",
          "people",
          "parents",
          "partners",
          "siblings",
          "companions",
          "showCompanions",
          "standalone",
          "hidden",
          "opened",
          "changes"
        ],
        "additionalProperties": false
      },
      "FamilyTreeCreateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "rootCharacterId": {
            "description": "The character it grows from, from character_list.",
            "type": "string"
          },
          "depth": {
            "description": "How many steps of kinship it reaches. Default: all of the connected family.",
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "parentId": {
            "description": "Where it goes: the Characters section, a cast, a family tree or a hierarchy (ids from character_list). Default: the Characters section.",
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "FamilyTreeCreateResponse": {
        "type": "object",
        "properties": {
          "treeId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "treeId",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilyTreeUpdateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "rootCharacterId": {
            "description": "The character it grows from; null for none.",
            "type": [
              "string",
              "null"
            ]
          },
          "depth": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 50
              },
              {
                "type": "null"
              }
            ]
          },
          "hide": {
            "description": "Characters to fold away from it.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "show": {
            "description": "Characters folded away, to bring back.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "open": {
            "description": "Partners who married in, whose own families to show.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "close": {
            "description": "Partners whose own families to stop showing.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "showCompanions": {
            "description": "Whether it shows companions; false hides them all.",
            "type": "boolean"
          },
          "place": {
            "description": "Companions to place on it by themselves.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unplace": {
            "description": "Companions placed by themselves, to take off it.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "FamilyTreeUpdateResponse": {
        "type": "object",
        "properties": {
          "treeId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "treeId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "FamilyTreeRemoveResponse": {
        "type": "object",
        "properties": {
          "treeId": {
            "type": "string"
          },
          "charactersTrashed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "treeId",
          "charactersTrashed",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyListResponse": {
        "type": "object",
        "properties": {
          "hierarchies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "preset": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "army",
                        "navy",
                        "court",
                        "company",
                        "guild",
                        "custom"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "roles": {
                  "type": "number"
                },
                "posts": {
                  "type": "number",
                  "description": "Posts open at the latest point of the story."
                },
                "vacant": {
                  "type": "number",
                  "description": "Of those, how many no one holds."
                }
              },
              "required": [
                "id",
                "title",
                "preset",
                "roles",
                "posts",
                "vacant"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "hierarchies"
        ],
        "additionalProperties": false
      },
      "HierarchyGetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "preset": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "army",
                  "navy",
                  "court",
                  "company",
                  "guild",
                  "custom"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "roles": {
            "type": "number"
          },
          "posts": {
            "type": "number",
            "description": "Posts open at the latest point of the story."
          },
          "vacant": {
            "type": "number",
            "description": "Of those, how many no one holds."
          },
          "asOf": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "roleList": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "note": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "posts": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string",
                        "description": "Its own name; empty when it is known by its role's."
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "active",
                          "ended",
                          "later"
                        ],
                        "description": "Whether the post exists as of the moment."
                      },
                      "from": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "ref": {
                                "type": "string",
                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                              },
                              "label": {
                                "type": "string",
                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                              },
                              "placed": {
                                "type": "boolean",
                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                              }
                            },
                            "required": [
                              "ref",
                              "label",
                              "placed"
                            ],
                            "additionalProperties": false,
                            "description": "A moment of the story."
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "until": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "ref": {
                                "type": "string",
                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                              },
                              "label": {
                                "type": "string",
                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                              },
                              "placed": {
                                "type": "boolean",
                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                              }
                            },
                            "required": [
                              "ref",
                              "label",
                              "placed"
                            ],
                            "additionalProperties": false,
                            "description": "A moment of the story."
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "reportsToPostId": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "alsoReportsTo": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "postId": {
                              "type": "string"
                            },
                            "from": {
                              "anyOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "ref": {
                                      "type": "string",
                                      "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                    },
                                    "label": {
                                      "type": "string",
                                      "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                    },
                                    "placed": {
                                      "type": "boolean",
                                      "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                    }
                                  },
                                  "required": [
                                    "ref",
                                    "label",
                                    "placed"
                                  ],
                                  "additionalProperties": false,
                                  "description": "A moment of the story."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "until": {
                              "anyOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "ref": {
                                      "type": "string",
                                      "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                    },
                                    "label": {
                                      "type": "string",
                                      "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                    },
                                    "placed": {
                                      "type": "boolean",
                                      "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                    }
                                  },
                                  "required": [
                                    "ref",
                                    "label",
                                    "placed"
                                  ],
                                  "additionalProperties": false,
                                  "description": "A moment of the story."
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "inForce": {
                              "type": "boolean"
                            }
                          },
                          "required": [
                            "postId",
                            "from",
                            "until",
                            "inForce"
                          ],
                          "additionalProperties": false
                        }
                      },
                      "holder": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "holdingId": {
                                "type": "string"
                              },
                              "postId": {
                                "type": "string"
                              },
                              "post": {
                                "type": "string"
                              },
                              "characterId": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "from": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "ref": {
                                        "type": "string",
                                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                      },
                                      "label": {
                                        "type": "string",
                                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                      },
                                      "placed": {
                                        "type": "boolean",
                                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                      }
                                    },
                                    "required": [
                                      "ref",
                                      "label",
                                      "placed"
                                    ],
                                    "additionalProperties": false,
                                    "description": "A moment of the story."
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "When they took the post; null: before the story."
                              },
                              "until": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "ref": {
                                        "type": "string",
                                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                      },
                                      "label": {
                                        "type": "string",
                                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                      },
                                      "placed": {
                                        "type": "boolean",
                                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                      }
                                    },
                                    "required": [
                                      "ref",
                                      "label",
                                      "placed"
                                    ],
                                    "additionalProperties": false,
                                    "description": "A moment of the story."
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "When they left it, as kept; a death is worked out into `ending`."
                              },
                              "why": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": [
                                      "died",
                                      "promoted",
                                      "demoted",
                                      "transferred",
                                      "left",
                                      "removed"
                                    ]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "ending": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "moment": {
                                        "anyOf": [
                                          {
                                            "type": "object",
                                            "properties": {
                                              "ref": {
                                                "type": "string",
                                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                              },
                                              "label": {
                                                "type": "string",
                                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                              },
                                              "placed": {
                                                "type": "boolean",
                                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                              }
                                            },
                                            "required": [
                                              "ref",
                                              "label",
                                              "placed"
                                            ],
                                            "additionalProperties": false,
                                            "description": "A moment of the story."
                                          },
                                          {
                                            "type": "null"
                                          }
                                        ]
                                      },
                                      "why": {
                                        "type": "string",
                                        "enum": [
                                          "died",
                                          "promoted",
                                          "demoted",
                                          "transferred",
                                          "left",
                                          "removed"
                                        ]
                                      }
                                    },
                                    "required": [
                                      "moment",
                                      "why"
                                    ],
                                    "additionalProperties": false
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "When and why it ends, worked out."
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "active",
                                  "ended",
                                  "later"
                                ],
                                "description": "Where the tie stands as of the moment: in force, over, or still to come."
                              }
                            },
                            "required": [
                              "holdingId",
                              "postId",
                              "post",
                              "characterId",
                              "name",
                              "from",
                              "until",
                              "why",
                              "ending",
                              "status"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "vacant": {
                        "type": "boolean"
                      },
                      "vacantSince": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "ref": {
                                "type": "string",
                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                              },
                              "label": {
                                "type": "string",
                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                              },
                              "placed": {
                                "type": "boolean",
                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                              }
                            },
                            "required": [
                              "ref",
                              "label",
                              "placed"
                            ],
                            "additionalProperties": false,
                            "description": "A moment of the story."
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "status",
                      "from",
                      "until",
                      "reportsToPostId",
                      "alsoReportsTo",
                      "holder",
                      "vacant",
                      "vacantSince"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "id",
                "name",
                "note",
                "posts"
              ],
              "additionalProperties": false
            },
            "description": "Its roles, highest first."
          },
          "holdings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "holdingId": {
                  "type": "string"
                },
                "postId": {
                  "type": "string"
                },
                "post": {
                  "type": "string"
                },
                "characterId": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "from": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they took the post; null: before the story."
                },
                "until": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                        },
                        "label": {
                          "type": "string",
                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                        },
                        "placed": {
                          "type": "boolean",
                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                        }
                      },
                      "required": [
                        "ref",
                        "label",
                        "placed"
                      ],
                      "additionalProperties": false,
                      "description": "A moment of the story."
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When they left it, as kept; a death is worked out into `ending`."
                },
                "why": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "died",
                        "promoted",
                        "demoted",
                        "transferred",
                        "left",
                        "removed"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "ending": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "moment": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "why": {
                          "type": "string",
                          "enum": [
                            "died",
                            "promoted",
                            "demoted",
                            "transferred",
                            "left",
                            "removed"
                          ]
                        }
                      },
                      "required": [
                        "moment",
                        "why"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "When and why it ends, worked out."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "ended",
                    "later"
                  ],
                  "description": "Where the tie stands as of the moment: in force, over, or still to come."
                }
              },
              "required": [
                "holdingId",
                "postId",
                "post",
                "characterId",
                "name",
                "from",
                "until",
                "why",
                "ending",
                "status"
              ],
              "additionalProperties": false
            },
            "description": "Every holding of a live character, earliest first."
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string",
                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                },
                "label": {
                  "type": "string",
                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                },
                "placed": {
                  "type": "boolean",
                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                }
              },
              "required": [
                "ref",
                "label",
                "placed"
              ],
              "additionalProperties": false,
              "description": "A moment of the story."
            }
          }
        },
        "required": [
          "id",
          "title",
          "preset",
          "roles",
          "posts",
          "vacant",
          "asOf",
          "roleList",
          "holdings",
          "changes"
        ],
        "additionalProperties": false
      },
      "HierarchyGetCharacterResponse": {
        "type": "object",
        "properties": {
          "character": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "additionalProperties": false
          },
          "asOf": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "ref": {
                    "type": "string",
                    "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                  },
                  "label": {
                    "type": "string",
                    "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                  },
                  "placed": {
                    "type": "boolean",
                    "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                  }
                },
                "required": [
                  "ref",
                  "label",
                  "placed"
                ],
                "additionalProperties": false,
                "description": "A moment of the story."
              },
              {
                "type": "null"
              }
            ]
          },
          "hierarchies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hierarchyId": {
                  "type": "string"
                },
                "hierarchy": {
                  "type": "string"
                },
                "holding": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "holdingId": {
                          "type": "string"
                        },
                        "postId": {
                          "type": "string"
                        },
                        "post": {
                          "type": "string"
                        },
                        "characterId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "from": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When they took the post; null: before the story."
                        },
                        "until": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "ref": {
                                  "type": "string",
                                  "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                },
                                "placed": {
                                  "type": "boolean",
                                  "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                }
                              },
                              "required": [
                                "ref",
                                "label",
                                "placed"
                              ],
                              "additionalProperties": false,
                              "description": "A moment of the story."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When they left it, as kept; a death is worked out into `ending`."
                        },
                        "why": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": [
                                "died",
                                "promoted",
                                "demoted",
                                "transferred",
                                "left",
                                "removed"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "ending": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "moment": {
                                  "anyOf": [
                                    {
                                      "type": "object",
                                      "properties": {
                                        "ref": {
                                          "type": "string",
                                          "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                        },
                                        "label": {
                                          "type": "string",
                                          "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                        },
                                        "placed": {
                                          "type": "boolean",
                                          "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                        }
                                      },
                                      "required": [
                                        "ref",
                                        "label",
                                        "placed"
                                      ],
                                      "additionalProperties": false,
                                      "description": "A moment of the story."
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "why": {
                                  "type": "string",
                                  "enum": [
                                    "died",
                                    "promoted",
                                    "demoted",
                                    "transferred",
                                    "left",
                                    "removed"
                                  ]
                                }
                              },
                              "required": [
                                "moment",
                                "why"
                              ],
                              "additionalProperties": false
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When and why it ends, worked out."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "active",
                            "ended",
                            "later"
                          ],
                          "description": "Where the tie stands as of the moment: in force, over, or still to come."
                        }
                      },
                      "required": [
                        "holdingId",
                        "postId",
                        "post",
                        "characterId",
                        "name",
                        "from",
                        "until",
                        "why",
                        "ending",
                        "status"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The post they hold as of the moment; null when none."
                },
                "role": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "reportsTo": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "postId": {
                          "type": "string"
                        },
                        "post": {
                          "type": "string"
                        },
                        "holder": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "name": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "id",
                                "name"
                              ],
                              "additionalProperties": false
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "postId",
                        "post",
                        "holder"
                      ],
                      "additionalProperties": false
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "alsoReportsTo": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "postId": {
                        "type": "string"
                      },
                      "post": {
                        "type": "string"
                      },
                      "holder": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "id",
                              "name"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "postId",
                      "post",
                      "holder"
                    ],
                    "additionalProperties": false
                  }
                },
                "commands": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "postId": {
                        "type": "string"
                      },
                      "post": {
                        "type": "string"
                      },
                      "holder": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "id",
                              "name"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "postId",
                      "post",
                      "holder"
                    ],
                    "additionalProperties": false
                  }
                },
                "holdings": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "holdingId": {
                        "type": "string"
                      },
                      "postId": {
                        "type": "string"
                      },
                      "post": {
                        "type": "string"
                      },
                      "characterId": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "from": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "ref": {
                                "type": "string",
                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                              },
                              "label": {
                                "type": "string",
                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                              },
                              "placed": {
                                "type": "boolean",
                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                              }
                            },
                            "required": [
                              "ref",
                              "label",
                              "placed"
                            ],
                            "additionalProperties": false,
                            "description": "A moment of the story."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "When they took the post; null: before the story."
                      },
                      "until": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "ref": {
                                "type": "string",
                                "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                              },
                              "label": {
                                "type": "string",
                                "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                              },
                              "placed": {
                                "type": "boolean",
                                "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                              }
                            },
                            "required": [
                              "ref",
                              "label",
                              "placed"
                            ],
                            "additionalProperties": false,
                            "description": "A moment of the story."
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "When they left it, as kept; a death is worked out into `ending`."
                      },
                      "why": {
                        "anyOf": [
                          {
                            "type": "string",
                            "enum": [
                              "died",
                              "promoted",
                              "demoted",
                              "transferred",
                              "left",
                              "removed"
                            ]
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "ending": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "moment": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "ref": {
                                        "type": "string",
                                        "description": "The moment as tools take it: \"before\", \"scene:<id>\" or \"event:<id>\"."
                                      },
                                      "label": {
                                        "type": "string",
                                        "description": "What Dabble shows for it: \"9.2 The Harbour Sale\", \"Aldric Dies (event at 5.3)\"."
                                      },
                                      "placed": {
                                        "type": "boolean",
                                        "description": "Whether it is in Reading Order. An event in no scene is placed by its date, among its timeline’s events that are in scenes; a fact at one it cannot place (undated) shows only at the latest."
                                      }
                                    },
                                    "required": [
                                      "ref",
                                      "label",
                                      "placed"
                                    ],
                                    "additionalProperties": false,
                                    "description": "A moment of the story."
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "why": {
                                "type": "string",
                                "enum": [
                                  "died",
                                  "promoted",
                                  "demoted",
                                  "transferred",
                                  "left",
                                  "removed"
                                ]
                              }
                            },
                            "required": [
                              "moment",
                              "why"
                            ],
                            "additionalProperties": false
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "When and why it ends, worked out."
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "active",
                          "ended",
                          "later"
                        ],
                        "description": "Where the tie stands as of the moment: in force, over, or still to come."
                      }
                    },
                    "required": [
                      "holdingId",
                      "postId",
                      "post",
                      "characterId",
                      "name",
                      "from",
                      "until",
                      "why",
                      "ending",
                      "status"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "hierarchyId",
                "hierarchy",
                "holding",
                "role",
                "reportsTo",
                "alsoReportsTo",
                "commands",
                "holdings"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "character",
          "asOf",
          "hierarchies"
        ],
        "additionalProperties": false
      },
      "HierarchyCreateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "preset": {
            "description": "What it starts from. Default: custom.",
            "type": "string",
            "enum": [
              "army",
              "navy",
              "court",
              "company",
              "guild",
              "custom"
            ]
          },
          "roles": {
            "description": "Its roles, highest first. Default: the preset's.",
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "note": {
                  "description": "What the role means in the story: its powers, duties, who may hold it.",
                  "type": "string",
                  "maxLength": 5000
                }
              },
              "required": [
                "name"
              ]
            }
          },
          "parentId": {
            "description": "Where it goes: the Characters section, a cast, a family tree or a hierarchy (ids from character_list). Default: the Characters section.",
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "HierarchyCreateResponse": {
        "type": "object",
        "properties": {
          "hierarchyId": {
            "type": "string"
          },
          "roles": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "hierarchyId",
          "roles",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyUpdateRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "HierarchyUpdateResponse": {
        "type": "object",
        "properties": {
          "hierarchyId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "hierarchyId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyRemoveResponse": {
        "type": "object",
        "properties": {
          "hierarchyId": {
            "type": "string"
          },
          "charactersTrashed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "hierarchyId",
          "charactersTrashed",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyAddRoleRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "note": {
            "description": "What the role means in the story: its powers, duties, who may hold it.",
            "type": "string",
            "maxLength": 5000
          },
          "aboveRoleId": {
            "description": "The role to put it just above. Default: at the bottom.",
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "HierarchyAddRoleResponse": {
        "type": "object",
        "properties": {
          "roleId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "roleId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyUpdateRoleRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "note": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 5000
              },
              {
                "type": "null"
              }
            ]
          },
          "aboveRoleId": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": false
      },
      "HierarchyUpdateRoleResponse": {
        "type": "object",
        "properties": {
          "roleId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "roleId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyRemoveRoleResponse": {
        "type": "object",
        "properties": {
          "roleId": {
            "type": "string"
          },
          "postsRemoved": {
            "type": "number"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "roleId",
          "postsRemoved",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyAddPostRequest": {
        "type": "object",
        "properties": {
          "roleId": {
            "type": "string",
            "description": "The role it is at, from hierarchy_get."
          },
          "name": {
            "description": "Its name. Default: known by its role's.",
            "type": "string",
            "maxLength": 300
          },
          "reportsToPostId": {
            "description": "The post it reports to. Default: none, at the top.",
            "type": "string"
          },
          "alsoReportsTo": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "postId": {
                  "type": "string"
                },
                "from": {
                  "type": "string",
                  "maxLength": 64,
                  "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                },
                "until": {
                  "type": "string",
                  "maxLength": 64,
                  "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                }
              },
              "required": [
                "postId"
              ]
            },
            "description": "Other posts it reports to as well, each of a higher role, with when each line begins and ends."
          },
          "from": {
            "description": "When the post is made. Default: before the story.",
            "type": "string",
            "maxLength": 64
          },
          "until": {
            "description": "When it is done away with. Default: never.",
            "type": "string",
            "maxLength": 64
          },
          "holderId": {
            "description": "A character to hold it from when it is made, from character_list.",
            "type": "string"
          }
        },
        "required": [
          "roleId"
        ],
        "additionalProperties": false
      },
      "HierarchyAddPostResponse": {
        "type": "object",
        "properties": {
          "postId": {
            "type": "string"
          },
          "holdingId": {
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "postId",
          "holdingId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyUpdatePostRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 300
          },
          "roleId": {
            "type": "string"
          },
          "reportsToPostId": {
            "type": [
              "string",
              "null"
            ]
          },
          "alsoReportsTo": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "postId": {
                  "type": "string"
                },
                "from": {
                  "type": "string",
                  "maxLength": 64,
                  "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                },
                "until": {
                  "type": "string",
                  "maxLength": 64,
                  "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
                }
              },
              "required": [
                "postId"
              ]
            },
            "description": "Other posts it reports to as well, each of a higher role, with when each line begins and ends."
          },
          "from": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "HierarchyUpdatePostResponse": {
        "type": "object",
        "properties": {
          "postId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "postId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyRemovePostResponse": {
        "type": "object",
        "properties": {
          "postId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "postId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyAppointRequest": {
        "type": "object",
        "properties": {
          "postId": {
            "type": "string",
            "description": "Post id from hierarchy_get."
          },
          "characterId": {
            "type": "string",
            "description": "Character id from character_list."
          },
          "from": {
            "type": "string",
            "maxLength": 64,
            "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
          },
          "until": {
            "type": "string",
            "maxLength": 64,
            "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
          },
          "why": {
            "description": "Why it ended. Default: left.",
            "type": "string",
            "enum": [
              "left",
              "removed",
              "promoted",
              "demoted",
              "transferred"
            ]
          }
        },
        "required": [
          "postId",
          "characterId"
        ],
        "additionalProperties": false
      },
      "HierarchyAppointResponse": {
        "type": "object",
        "properties": {
          "holdingId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "holdingId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyUpdateHoldingRequest": {
        "type": "object",
        "properties": {
          "postId": {
            "type": "string"
          },
          "characterId": {
            "type": "string"
          },
          "from": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "until": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64,
                "description": "A moment of the story: \"before\" (before it starts), \"scene:<sceneId>\" (from dabble_get_outline) or \"event:<eventId>\" (from timeline_get). A fact at an event counts from the scene the event is the present of."
              },
              {
                "type": "null"
              }
            ]
          },
          "why": {
            "type": "string",
            "enum": [
              "left",
              "removed",
              "promoted",
              "demoted",
              "transferred"
            ]
          }
        },
        "additionalProperties": false
      },
      "HierarchyUpdateHoldingResponse": {
        "type": "object",
        "properties": {
          "holdingId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "holdingId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyRemoveHoldingResponse": {
        "type": "object",
        "properties": {
          "holdingId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "holdingId",
          "rev"
        ],
        "additionalProperties": false
      },
      "HierarchyMoveHolderRequest": {
        "type": "object",
        "properties": {
          "toPostId": {
            "type": "string",
            "description": "The post they take."
          },
          "at": {
            "type": "string",
            "maxLength": 64,
            "description": "When: \"scene:<sceneId>\" or \"event:<eventId>\"."
          },
          "why": {
            "type": "string",
            "enum": [
              "promoted",
              "demoted",
              "transferred"
            ]
          }
        },
        "required": [
          "toPostId",
          "at",
          "why"
        ],
        "additionalProperties": false
      },
      "HierarchyMoveHolderResponse": {
        "type": "object",
        "properties": {
          "holdingId": {
            "type": "string",
            "description": "Their holding of the new post."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "holdingId",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationListResponse": {
        "type": "object",
        "properties": {
          "places": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "depth": {
                  "type": "number",
                  "description": "0 for a place straight under Locations, 1 for one inside it, and so on."
                },
                "parentId": {
                  "description": "The place it is in, or null.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "summary": {
                  "type": "string"
                },
                "hasBanner": {
                  "type": "boolean"
                }
              },
              "required": [
                "id",
                "name",
                "depth",
                "parentId",
                "summary",
                "hasBanner"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "places"
        ],
        "additionalProperties": false
      },
      "LocationGetResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "subtitle": {
            "type": "string"
          },
          "bannerUrl": {
            "type": "string"
          },
          "path": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "The places it is in, nearest first."
          },
          "places": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "The places straight inside it."
          },
          "sheet": {
            "type": "object",
            "properties": {
              "sections": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "heading": {
                      "description": "Section heading, or null for terms before the first heading.",
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "terms": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "term": {
                            "type": "string"
                          },
                          "value": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "term",
                          "value"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "heading",
                    "terms"
                  ],
                  "additionalProperties": false
                }
              },
              "intro": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Paragraphs before the first term list, in order."
              },
              "prose": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The other paragraphs that are not part of any term list, in order."
              }
            },
            "required": [
              "sections",
              "intro",
              "prose"
            ],
            "additionalProperties": false
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "content": {
                  "type": "string",
                  "description": "The card text as plain text."
                },
                "labels": {
                  "description": "The texts of the labels on the card, when it has any.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "title",
                "content"
              ],
              "additionalProperties": false
            }
          },
          "pages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title"
              ],
              "additionalProperties": false
            }
          },
          "scenes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "The scenes set here."
          },
          "residents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "The characters who live here."
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ],
              "additionalProperties": false
            },
            "description": "The timeline events set here."
          }
        },
        "required": [
          "id",
          "name",
          "path",
          "places",
          "sheet",
          "notes",
          "pages",
          "scenes",
          "residents",
          "events"
        ],
        "additionalProperties": false
      },
      "LocationCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "parentId": {
            "description": "The place it is in, from location_list, or the Locations section (\"locations\"). Omit for a place straight under Locations.",
            "type": "string"
          },
          "subtitle": {
            "type": "string",
            "maxLength": 300
          },
          "excerpt": {
            "description": "A short description shown on its card.",
            "type": "string",
            "maxLength": 2000
          },
          "sheet": {
            "description": "Sections of term/value pairs, e.g. Climate: Temperate, under the heading \"Geography\".",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "heading": {
                  "type": "string",
                  "maxLength": 300
                },
                "terms": {
                  "maxItems": 50,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "term": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "value": {
                        "type": "string",
                        "maxLength": 5000
                      }
                    },
                    "required": [
                      "term",
                      "value"
                    ]
                  }
                }
              },
              "required": [
                "terms"
              ]
            }
          },
          "notes": {
            "description": "Free-form text after the sheet. Plain text or light Markdown.",
            "type": "string",
            "maxLength": 20000
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "LocationCreateResponse": {
        "type": "object",
        "properties": {
          "placeId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "placeId",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 300
          },
          "updateReferences": {
            "description": "On a rename, also replace the old name across the project (scenes, notes, summaries and titles), as Dabble's rename prompt would, and save the rename as a named version. Default true; pass false to rename only.",
            "type": "boolean"
          },
          "subtitle": {
            "type": "string",
            "maxLength": 300
          },
          "excerpt": {
            "type": "string",
            "maxLength": 2000
          },
          "notes": {
            "description": "Free-form text after the sheet. Replaces what is there unless append is true.",
            "type": "string",
            "maxLength": 20000
          },
          "append": {
            "type": "boolean"
          },
          "intro": {
            "description": "Free-form text before the sheet, replacing what is there. Empty removes it, as when its content has moved into the sheet.",
            "type": "string",
            "maxLength": 20000
          },
          "replace": {
            "type": "object",
            "properties": {
              "find": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The passage to replace, quoted as the text reads. It may run across paragraphs, bullets and headings when quoted as the markdown read shows it (`## Heading`, `- bullet`, blocks apart by a blank line); spacing and line breaks need not match exactly."
              },
              "with": {
                "type": "string",
                "maxLength": 20000,
                "description": "The replacement, in plain text or light Markdown. Empty removes the passage, and a paragraph, bullet or heading left with no text is removed with it."
              },
              "occurrence": {
                "description": "Which occurrence (1-based) when the passage repeats.",
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "find",
              "with"
            ]
          },
          "removeSections": {
            "description": "Headings of sections to remove, each with everything under it up to the next heading of the same or a higher level, the next line in bold, or the property list. A heading is a #-heading of any level or a line in bold (**Appearance**); case, spacing and a trailing colon do not matter. Returns what went and saves a named version.",
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          },
          "includeSheet": {
            "description": "Let removeSections remove a property-list (sheet) heading, with all its terms and values. Without it a sheet heading is refused, so a stray call cannot wipe a template.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "LocationUpdateResponse": {
        "type": "object",
        "properties": {
          "placeId": {
            "type": "string"
          },
          "changed": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "removed": {
            "description": "What the call removed, when it took out whole blocks.",
            "type": "object",
            "properties": {
              "blocks": {
                "type": "number",
                "description": "Paragraphs, bullets and headings taken out whole."
              },
              "headings": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The headings among them."
              },
              "paragraphs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The opening words of every other block that went."
              },
              "images": {
                "type": "number",
                "description": "Images that went with them."
              }
            },
            "required": [
              "blocks",
              "headings",
              "paragraphs",
              "images"
            ],
            "additionalProperties": false
          },
          "sections": {
            "description": "The sections removeSections took off, as their headings read.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "keptSheet": {
            "description": "Names that also head a property list, which was left alone (pass includeSheet to remove it too).",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "version": {
            "description": "After a rename: the named version it was saved as in version history.",
            "type": "string"
          },
          "namesReplaced": {
            "description": "After a rename: how many times the old name was replaced across the project, scenes included.",
            "type": "number"
          },
          "oldNameUses": {
            "description": "After a rename: where the old name is still written as plain text, no longer linked (a name another linked document also goes by is left for the author).",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "uses": {
                  "type": "number"
                },
                "documents": {
                  "type": "number"
                },
                "manuscript": {
                  "type": "number",
                  "description": "How many of those documents are in the manuscript, which Connect cannot edit."
                }
              },
              "required": [
                "name",
                "uses",
                "documents",
                "manuscript"
              ],
              "additionalProperties": false
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "placeId",
          "changed",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationSetTermsRequest": {
        "type": "object",
        "properties": {
          "terms": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "heading": {
                  "description": "Section heading, e.g. \"Geography\".",
                  "type": "string",
                  "maxLength": 300
                },
                "term": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "value": {
                  "type": "string",
                  "maxLength": 5000
                }
              },
              "required": [
                "term",
                "value"
              ]
            }
          }
        },
        "required": [
          "terms"
        ],
        "additionalProperties": false
      },
      "LocationSetTermsResponse": {
        "type": "object",
        "properties": {
          "placeId": {
            "type": "string"
          },
          "updated": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "added": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "placeId",
          "updated",
          "added",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationRemoveResponse": {
        "type": "object",
        "properties": {
          "placeId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "placeId",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationSetScenePlaceRequest": {
        "type": "object",
        "properties": {
          "placeId": {
            "description": "Place id from location_list, or null for none.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "placeId"
        ],
        "additionalProperties": false
      },
      "LocationSetScenePlaceResponse": {
        "type": "object",
        "properties": {
          "sceneId": {
            "type": "string"
          },
          "placeId": {
            "type": [
              "string",
              "null"
            ]
          },
          "previous": {
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "sceneId",
          "placeId",
          "previous",
          "rev"
        ],
        "additionalProperties": false
      },
      "LocationSetHomeRequest": {
        "type": "object",
        "properties": {
          "placeId": {
            "description": "Place id from location_list, or null for none.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "placeId"
        ],
        "additionalProperties": false
      },
      "LocationSetHomeResponse": {
        "type": "object",
        "properties": {
          "characterId": {
            "type": "string"
          },
          "placeId": {
            "type": [
              "string",
              "null"
            ]
          },
          "previous": {
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "characterId",
          "placeId",
          "previous",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotebookGetTreeResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "folder",
                    "page",
                    "cast",
                    "character",
                    "place"
                  ],
                  "description": "cast, character and place are the owners of pages kept outside the notebook."
                },
                "depth": {
                  "type": "number",
                  "description": "Nesting depth, 0 at the top."
                },
                "words": {
                  "type": "number"
                },
                "misfiled": {
                  "description": "A page under another page, which Dabble does not allow: move it into a folder.",
                  "type": "boolean"
                }
              },
              "required": [
                "id",
                "title",
                "kind",
                "depth"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false
      },
      "NotebookReadPageResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "bannerUrl": {
            "description": "The banner image above the page, when it has one.",
            "type": "string"
          },
          "text": {
            "type": "string",
            "description": "This page of the text."
          },
          "offset": {
            "type": "number",
            "description": "Character offset this page starts at."
          },
          "nextOffset": {
            "description": "Offset to continue from, or null when this page is the last.",
            "type": [
              "number",
              "null"
            ]
          },
          "totalLength": {
            "type": "number",
            "description": "Length of the whole text in characters."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "content": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title",
                "content"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "id",
          "title",
          "text",
          "offset",
          "nextOffset",
          "totalLength",
          "notes"
        ],
        "additionalProperties": false
      },
      "NotebookCreatePageRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "parentId": {
            "description": "Folder, character or place id to file it under, or the notebook itself (\"notebook\"). Defaults to the notebook root.",
            "type": "string"
          },
          "text": {
            "description": "Starting page text.",
            "type": "string",
            "maxLength": 20000
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "NotebookCreatePageResponse": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pageId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotebookCreateFolderRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "parentId": {
            "description": "Folder or cast id to nest under, or the notebook itself (\"notebook\"). Defaults to the notebook root.",
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "NotebookCreateFolderResponse": {
        "type": "object",
        "properties": {
          "folderId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "folderId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotebookAppendPageRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "Text to append. Plain text or light Markdown. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click."
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "NotebookAppendPageResponse": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pageId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotebookUpdatePageRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "A new title.",
            "type": "string",
            "maxLength": 300
          },
          "updateReferences": {
            "description": "On a rename, also replace the old name across the project (scenes, notes, summaries and titles), as Dabble's rename prompt would, and save the rename as a named version. Default true; pass false to rename only.",
            "type": "boolean"
          },
          "text": {
            "description": "New text for the whole page. Plain text or light Markdown. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click.",
            "type": "string",
            "maxLength": 20000
          },
          "replace": {
            "type": "object",
            "properties": {
              "find": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The passage to replace, quoted as the text reads. It may run across paragraphs, bullets and headings when quoted as the markdown read shows it (`## Heading`, `- bullet`, blocks apart by a blank line); spacing and line breaks need not match exactly."
              },
              "with": {
                "type": "string",
                "maxLength": 20000,
                "description": "The replacement, in plain text or light Markdown. Empty removes the passage, and a paragraph, bullet or heading left with no text is removed with it."
              },
              "occurrence": {
                "description": "Which occurrence (1-based) when the passage repeats.",
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "find",
              "with"
            ]
          },
          "removeSections": {
            "description": "Headings of sections to remove, each with everything under it up to the next heading of the same or a higher level, the next line in bold, or the property list. A heading is a #-heading of any level or a line in bold (**Appearance**); case, spacing and a trailing colon do not matter. Returns what went and saves a named version.",
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          },
          "includeSheet": {
            "description": "Let removeSections remove a property-list (sheet) heading, with all its terms and values. Without it a sheet heading is refused, so a stray call cannot wipe a template.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "NotebookUpdatePageResponse": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string"
          },
          "replaced": {
            "description": "The passage that was swapped out, when the call replaced one.",
            "type": "object",
            "properties": {
              "index": {
                "type": "number"
              },
              "length": {
                "type": "number"
              }
            },
            "required": [
              "index",
              "length"
            ],
            "additionalProperties": false
          },
          "removed": {
            "description": "What the call removed, when it took out whole blocks.",
            "type": "object",
            "properties": {
              "blocks": {
                "type": "number",
                "description": "Paragraphs, bullets and headings taken out whole."
              },
              "headings": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The headings among them."
              },
              "paragraphs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The opening words of every other block that went."
              },
              "images": {
                "type": "number",
                "description": "Images that went with them."
              }
            },
            "required": [
              "blocks",
              "headings",
              "paragraphs",
              "images"
            ],
            "additionalProperties": false
          },
          "sections": {
            "description": "The sections removeSections took off, as their headings read.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "keptSheet": {
            "description": "Names that also head a property list, which was left alone (pass includeSheet to remove it too).",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "version": {
            "description": "After a rename: the named version it was saved as in version history.",
            "type": "string"
          },
          "namesReplaced": {
            "description": "After a rename: how many times the old name was replaced across the project, scenes included.",
            "type": "number"
          },
          "oldNameUses": {
            "description": "After a rename: where the old name is still written as plain text, no longer linked (a name another linked document also goes by is left for the author).",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "uses": {
                  "type": "number"
                },
                "documents": {
                  "type": "number"
                },
                "manuscript": {
                  "type": "number",
                  "description": "How many of those documents are in the manuscript, which Connect cannot edit."
                }
              },
              "required": [
                "name",
                "uses",
                "documents",
                "manuscript"
              ],
              "additionalProperties": false
            }
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pageId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotebookRemoveResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "IdeasGetTreeResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "folder",
                    "idea",
                    "image"
                  ]
                },
                "depth": {
                  "type": "number",
                  "description": "Nesting depth, 0 at the top."
                },
                "words": {
                  "type": "number"
                },
                "subtitle": {
                  "description": "The one-line description an idea carries.",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "title",
                "kind",
                "depth"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "items"
        ],
        "additionalProperties": false
      },
      "IdeasReadIdeaResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "subtitle": {
            "type": "string"
          },
          "bannerColor": {
            "type": "string"
          },
          "bannerUrl": {
            "description": "The banner image above the idea, when it has one.",
            "type": "string"
          },
          "text": {
            "type": "string",
            "description": "This page of the text."
          },
          "offset": {
            "type": "number",
            "description": "Character offset this page starts at."
          },
          "nextOffset": {
            "description": "Offset to continue from, or null when this page is the last.",
            "type": [
              "number",
              "null"
            ]
          },
          "totalLength": {
            "type": "number",
            "description": "Length of the whole text in characters."
          }
        },
        "required": [
          "id",
          "title",
          "text",
          "offset",
          "nextOffset",
          "totalLength"
        ],
        "additionalProperties": false
      },
      "IdeasCreateIdeaRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "parentId": {
            "description": "Folder id to nest under. Defaults to the top of the Ideas notebook.",
            "type": "string"
          },
          "text": {
            "description": "Starting text.",
            "type": "string",
            "maxLength": 20000
          },
          "subtitle": {
            "description": "A one-line description shown under the title.",
            "type": "string",
            "maxLength": 300
          },
          "bannerColor": {
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black"
            ],
            "description": "Banner colour, one of: navy, blue, teal, green, yellow, amber, orange, coral, red, raspberry, pink, lavender, purple, taupe, brown, black."
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "IdeasCreateIdeaResponse": {
        "type": "object",
        "properties": {
          "ideaId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "ideaId",
          "rev"
        ],
        "additionalProperties": false
      },
      "IdeasCreateFolderRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "parentId": {
            "description": "Folder id to nest under. Defaults to the top of the Ideas notebook.",
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "IdeasCreateFolderResponse": {
        "type": "object",
        "properties": {
          "folderId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "folderId",
          "rev"
        ],
        "additionalProperties": false
      },
      "IdeasAppendIdeaRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "Text to append. Plain text or light Markdown. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click."
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "IdeasAppendIdeaResponse": {
        "type": "object",
        "properties": {
          "ideaId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "ideaId",
          "rev"
        ],
        "additionalProperties": false
      },
      "IdeasUpdateIdeaRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "A new title.",
            "type": "string",
            "maxLength": 300
          },
          "subtitle": {
            "description": "A new one-line description.",
            "type": "string",
            "maxLength": 300
          },
          "bannerColor": {
            "description": "A banner colour (navy, blue, teal, green, yellow, amber, orange, coral, red, raspberry, pink, lavender, purple, taupe, brown, black), or none to take the colour off.",
            "type": "string",
            "enum": [
              "navy",
              "blue",
              "teal",
              "green",
              "yellow",
              "amber",
              "orange",
              "coral",
              "red",
              "raspberry",
              "pink",
              "lavender",
              "purple",
              "taupe",
              "brown",
              "black",
              "none"
            ]
          },
          "text": {
            "description": "New text for the whole idea. Plain text or light Markdown. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click.",
            "type": "string",
            "maxLength": 20000
          },
          "replace": {
            "type": "object",
            "properties": {
              "find": {
                "type": "string",
                "minLength": 1,
                "maxLength": 20000,
                "description": "The passage to replace, quoted as the text reads. It may run across paragraphs, bullets and headings when quoted as the markdown read shows it (`## Heading`, `- bullet`, blocks apart by a blank line); spacing and line breaks need not match exactly."
              },
              "with": {
                "type": "string",
                "maxLength": 20000,
                "description": "The replacement, in plain text or light Markdown. Empty removes the passage, and a paragraph, bullet or heading left with no text is removed with it."
              },
              "occurrence": {
                "description": "Which occurrence (1-based) when the passage repeats.",
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "find",
              "with"
            ]
          }
        },
        "additionalProperties": false
      },
      "IdeasUpdateIdeaResponse": {
        "type": "object",
        "properties": {
          "ideaId": {
            "type": "string"
          },
          "replaced": {
            "description": "The passage that was swapped out, when the call replaced one.",
            "type": "object",
            "properties": {
              "index": {
                "type": "number"
              },
              "length": {
                "type": "number"
              }
            },
            "required": [
              "index",
              "length"
            ],
            "additionalProperties": false
          },
          "removed": {
            "description": "What the call removed, when it took out whole blocks.",
            "type": "object",
            "properties": {
              "blocks": {
                "type": "number",
                "description": "Paragraphs, bullets and headings taken out whole."
              },
              "headings": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The headings among them."
              },
              "paragraphs": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The opening words of every other block that went."
              },
              "images": {
                "type": "number",
                "description": "Images that went with them."
              }
            },
            "required": [
              "blocks",
              "headings",
              "paragraphs",
              "images"
            ],
            "additionalProperties": false
          },
          "version": {
            "description": "The version saved after the removal, so the author can go back.",
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "ideaId",
          "rev"
        ],
        "additionalProperties": false
      },
      "IdeasRemoveResponse": {
        "type": "object",
        "properties": {
          "ideaId": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "folder",
              "idea"
            ]
          },
          "ideasInside": {
            "type": "number",
            "description": "Ideas that went to the trash inside a folder."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "ideaId",
          "kind",
          "ideasInside",
          "rev"
        ],
        "additionalProperties": false
      },
      "ImagesSetAvatarRequest": {
        "type": "object",
        "properties": {
          "imageUrl": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "A public https link to a PNG, JPEG, WebP or GIF of at most 5 MB. Dabble fetches it once and keeps its own copy, so the link need not last. Pass null to take the picture off."
          },
          "crop": {
            "description": "The exact region of the picture to use, e.g. { x: 0.25, y: 0, width: 0.5, height: 0.5 } for the top middle. Dabble fills the slot from the middle of that region, so give it the slot's proportions to keep all of it. Omit crop and focus and Dabble chooses what to keep in view.",
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Left edge of the region, as a fraction of the picture's width (0 is the left edge)."
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Top edge of the region, as a fraction of the picture's height (0 is the top edge)."
              },
              "width": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Width of the region, as a fraction of the picture's width."
              },
              "height": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Height of the region, as a fraction of the picture's height."
              }
            },
            "required": [
              "x",
              "y",
              "width",
              "height"
            ]
          },
          "focus": {
            "description": "A point to keep in view, e.g. { x: 0.5, y: 0.3 } for a face in the upper middle. Dabble keeps as much of the picture as fits the slot around it. Pass crop or focus, not both.",
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Across the picture: 0 is the left edge, 1 the right."
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Down the picture: 0 is the top edge, 1 the bottom."
              }
            },
            "required": [
              "x",
              "y"
            ]
          },
          "replace": {
            "description": "Set true to replace a picture that is already there. Without it the call is refused, so a picture the author chose is never lost by accident.",
            "type": "boolean"
          }
        },
        "required": [
          "imageUrl"
        ],
        "additionalProperties": false
      },
      "ImagesSetAvatarResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "imageUrl": {
            "description": "The address of Dabble's copy now on the document, or null when it has none.",
            "type": [
              "string",
              "null"
            ]
          },
          "previousUrl": {
            "description": "The picture that was there before, or null when there was none.",
            "type": [
              "string",
              "null"
            ]
          },
          "changed": {
            "type": "boolean",
            "description": "False when the document already had exactly this picture, or none to remove."
          },
          "framed": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "crop",
                  "focus",
                  "auto",
                  "none"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "How the picture was cut to the slot: crop or focus as asked, auto when Dabble chose what to keep in view, none when it was kept as it came. Null when a picture was removed."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "imageUrl",
          "previousUrl",
          "changed",
          "framed",
          "rev"
        ],
        "additionalProperties": false
      },
      "ImagesSetBannerRequest": {
        "type": "object",
        "properties": {
          "imageUrl": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ],
            "description": "A public https link to a PNG, JPEG, WebP or GIF of at most 5 MB. Dabble fetches it once and keeps its own copy, so the link need not last. Pass null to take the picture off."
          },
          "crop": {
            "description": "The exact region of the picture to use, e.g. { x: 0.25, y: 0, width: 0.5, height: 0.5 } for the top middle. Dabble fills the slot from the middle of that region, so give it the slot's proportions to keep all of it. Omit crop and focus and Dabble chooses what to keep in view.",
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Left edge of the region, as a fraction of the picture's width (0 is the left edge)."
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Top edge of the region, as a fraction of the picture's height (0 is the top edge)."
              },
              "width": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Width of the region, as a fraction of the picture's width."
              },
              "height": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Height of the region, as a fraction of the picture's height."
              }
            },
            "required": [
              "x",
              "y",
              "width",
              "height"
            ]
          },
          "focus": {
            "description": "A point to keep in view, e.g. { x: 0.5, y: 0.3 } for a face in the upper middle. Dabble keeps as much of the picture as fits the slot around it. Pass crop or focus, not both.",
            "type": "object",
            "properties": {
              "x": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Across the picture: 0 is the left edge, 1 the right."
              },
              "y": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "description": "Down the picture: 0 is the top edge, 1 the bottom."
              }
            },
            "required": [
              "x",
              "y"
            ]
          },
          "replace": {
            "description": "Set true to replace a picture that is already there. Without it the call is refused, so a picture the author chose is never lost by accident.",
            "type": "boolean"
          }
        },
        "required": [
          "imageUrl"
        ],
        "additionalProperties": false
      },
      "ImagesSetBannerResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "imageUrl": {
            "description": "The address of Dabble's copy now on the document, or null when it has none.",
            "type": [
              "string",
              "null"
            ]
          },
          "previousUrl": {
            "description": "The picture that was there before, or null when there was none.",
            "type": [
              "string",
              "null"
            ]
          },
          "changed": {
            "type": "boolean",
            "description": "False when the document already had exactly this picture, or none to remove."
          },
          "framed": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "crop",
                  "focus",
                  "auto",
                  "none"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "How the picture was cut to the slot: crop or focus as asked, auto when Dabble chose what to keep in view, none when it was kept as it came. Null when a picture was removed."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "imageUrl",
          "previousUrl",
          "changed",
          "framed",
          "rev"
        ],
        "additionalProperties": false
      },
      "ImagesCreatePageRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "What the page is called: \"Map of Velara\"."
          },
          "imageUrl": {
            "description": "A public https link to a PNG, JPEG, WebP or GIF of at most 5 MB.",
            "type": "string",
            "maxLength": 2000
          },
          "parentId": {
            "description": "A notebook folder, character or place id (from notebook_get_tree, character_list or location_list), or an idea folder in the Ideas notebook. Defaults to the notebook.",
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "ImagesCreatePageResponse": {
        "type": "object",
        "properties": {
          "pageId": {
            "type": "string"
          },
          "parentId": {
            "type": "string"
          },
          "imageUrl": {
            "description": "The address of Dabble's copy the page shows, or null for none.",
            "type": [
              "string",
              "null"
            ]
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "pageId",
          "parentId",
          "imageUrl",
          "rev"
        ],
        "additionalProperties": false
      },
      "ImagesListAssetsResponse": {
        "type": "object",
        "properties": {
          "assets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "assetId": {
                  "type": "string",
                  "description": "The id images_rename_asset and images_remove_asset take."
                },
                "url": {
                  "type": "string",
                  "description": "The address of Dabble's copy of the whole image. Pass it as imageUrl to images_set_avatar or images_set_banner to use it."
                },
                "name": {
                  "description": "The author's name for it, usually the file name it was uploaded with.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "upload",
                    "stock"
                  ],
                  "description": "upload for one the author or an app added; stock for a stock photo they picked."
                },
                "width": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "height": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "projectId": {
                  "description": "The project it was first added in.",
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "addedAt": {
                  "type": "string",
                  "description": "ISO 8601."
                },
                "crops": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "url": {
                        "type": "string"
                      },
                      "kind": {
                        "type": "string",
                        "enum": [
                          "image",
                          "avatar",
                          "banner",
                          "cover"
                        ]
                      }
                    },
                    "required": [
                      "url",
                      "kind"
                    ],
                    "additionalProperties": false
                  },
                  "description": "The copies cut from it for a portrait, a banner or a cover."
                }
              },
              "required": [
                "assetId",
                "url",
                "name",
                "source",
                "width",
                "height",
                "projectId",
                "addedAt",
                "crops"
              ],
              "additionalProperties": false
            }
          },
          "total": {
            "type": "number",
            "description": "How many images match, which is more than are listed when truncated is true."
          },
          "truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "assets",
          "total",
          "truncated"
        ],
        "additionalProperties": false
      },
      "ImagesAddAssetRequest": {
        "type": "object",
        "properties": {
          "projectId": {
            "type": "string",
            "description": "Project id from dabble_list_projects: the project the image is added for."
          },
          "imageUrl": {
            "type": "string",
            "maxLength": 2000,
            "description": "A public https link to a PNG, JPEG, WebP or GIF of at most 5 MB."
          },
          "name": {
            "description": "A name for the image, shown under it in the library.",
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "projectId",
          "imageUrl"
        ],
        "additionalProperties": false
      },
      "ImagesAddAssetResponse": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "object",
            "properties": {
              "assetId": {
                "type": "string",
                "description": "The id images_rename_asset and images_remove_asset take."
              },
              "url": {
                "type": "string",
                "description": "The address of Dabble's copy of the whole image. Pass it as imageUrl to images_set_avatar or images_set_banner to use it."
              },
              "name": {
                "description": "The author's name for it, usually the file name it was uploaded with.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "source": {
                "type": "string",
                "enum": [
                  "upload",
                  "stock"
                ],
                "description": "upload for one the author or an app added; stock for a stock photo they picked."
              },
              "width": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "height": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "projectId": {
                "description": "The project it was first added in.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "addedAt": {
                "type": "string",
                "description": "ISO 8601."
              },
              "crops": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "image",
                        "avatar",
                        "banner",
                        "cover"
                      ]
                    }
                  },
                  "required": [
                    "url",
                    "kind"
                  ],
                  "additionalProperties": false
                },
                "description": "The copies cut from it for a portrait, a banner or a cover."
              }
            },
            "required": [
              "assetId",
              "url",
              "name",
              "source",
              "width",
              "height",
              "projectId",
              "addedAt",
              "crops"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "asset"
        ],
        "additionalProperties": false
      },
      "ImagesRenameAssetRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The new name."
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "ImagesRenameAssetResponse": {
        "type": "object",
        "properties": {
          "assetId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "assetId",
          "name"
        ],
        "additionalProperties": false
      },
      "ImagesRemoveAssetResponse": {
        "type": "object",
        "properties": {
          "assetId": {
            "type": "string"
          },
          "removed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The addresses taken out of the library: the image and its crops."
          }
        },
        "required": [
          "assetId",
          "removed"
        ],
        "additionalProperties": false
      },
      "NotesListResponse": {
        "type": "object",
        "properties": {
          "docs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "docId": {
                  "type": "string"
                },
                "docType": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "count": {
                  "type": "number",
                  "description": "Note cards on the doc."
                }
              },
              "required": [
                "docId",
                "docType",
                "title",
                "count"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "docs"
        ],
        "additionalProperties": false
      },
      "NotesGetResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "content": {
                  "type": "string",
                  "description": "The card text as plain text."
                },
                "labels": {
                  "description": "The texts of the labels on the card, when it has any.",
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "id",
                "title",
                "content"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "docId",
          "notes"
        ],
        "additionalProperties": false
      },
      "NotesAddRequest": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "The note body. Plain text or light Markdown. To link to another document of the project (a scene, chapter, character, page…), write @[Title](id) with its id: it becomes a mention the author can click."
          },
          "title": {
            "description": "Optional card title.",
            "type": "string",
            "maxLength": 300
          },
          "label": {
            "type": "object",
            "properties": {
              "text": {
                "description": "Label text, e.g. \"Needs research\".",
                "type": "string",
                "maxLength": 60
              },
              "color": {
                "description": "One of: navy, blue, teal, green, yellow, amber, orange, coral, red, raspberry, pink, lavender, purple, taupe, brown, black.",
                "type": "string",
                "enum": [
                  "navy",
                  "blue",
                  "teal",
                  "green",
                  "yellow",
                  "amber",
                  "orange",
                  "coral",
                  "red",
                  "raspberry",
                  "pink",
                  "lavender",
                  "purple",
                  "taupe",
                  "brown",
                  "black"
                ]
              }
            }
          }
        },
        "required": [
          "text"
        ],
        "additionalProperties": false
      },
      "NotesAddResponse": {
        "type": "object",
        "properties": {
          "noteId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "noteId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotesUpdateRequest": {
        "type": "object",
        "properties": {
          "text": {
            "description": "New body, or text to append.",
            "type": "string",
            "maxLength": 20000
          },
          "append": {
            "description": "Append text after the existing body instead of replacing it.",
            "type": "boolean"
          },
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "label": {
            "description": "A label to add to the card's labels.",
            "type": "object",
            "properties": {
              "text": {
                "description": "Label text, e.g. \"Needs research\".",
                "type": "string",
                "maxLength": 60
              },
              "color": {
                "description": "One of: navy, blue, teal, green, yellow, amber, orange, coral, red, raspberry, pink, lavender, purple, taupe, brown, black.",
                "type": "string",
                "enum": [
                  "navy",
                  "blue",
                  "teal",
                  "green",
                  "yellow",
                  "amber",
                  "orange",
                  "coral",
                  "red",
                  "raspberry",
                  "pink",
                  "lavender",
                  "purple",
                  "taupe",
                  "brown",
                  "black"
                ]
              }
            }
          }
        },
        "additionalProperties": false
      },
      "NotesUpdateResponse": {
        "type": "object",
        "properties": {
          "noteId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "noteId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "NotesRemoveResponse": {
        "type": "object",
        "properties": {
          "noteId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "noteId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CommentsGetResponse": {
        "type": "object",
        "properties": {
          "comments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "docId": {
                  "type": "string"
                },
                "docTitle": {
                  "type": "string"
                },
                "field": {
                  "type": "string",
                  "enum": [
                    "body",
                    "title",
                    "subtitle",
                    "author"
                  ],
                  "description": "Where the thread is: the doc's body, or its title, subtitle or author line."
                },
                "anchor": {
                  "type": "string",
                  "description": "The passage the thread is anchored to; empty when the anchor was lost."
                },
                "lastKnownText": {
                  "description": "For an orphaned thread: the passage it was on when its anchor was lost.",
                  "type": "string"
                },
                "author": {
                  "type": "string"
                },
                "content": {
                  "type": "string"
                },
                "createdAt": {
                  "type": "string"
                },
                "resolved": {
                  "type": "boolean"
                },
                "change": {
                  "description": "For a tracked-change thread: insert, delete, format, substitution, or moved.",
                  "type": "string"
                },
                "replies": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "author": {
                        "type": "string"
                      },
                      "content": {
                        "type": "string"
                      },
                      "createdAt": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "id",
                      "author",
                      "content",
                      "createdAt"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "id",
                "docId",
                "docTitle",
                "field",
                "anchor",
                "author",
                "content",
                "createdAt",
                "resolved",
                "replies"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "comments"
        ],
        "additionalProperties": false
      },
      "CommentsAddRequest": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "The passage to anchor to, quoted from manuscript_read."
          },
          "occurrence": {
            "description": "Which occurrence to use when the quote appears more than once (1-based).",
            "type": "integer",
            "minimum": 1
          },
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000,
            "description": "The comment."
          },
          "field": {
            "description": "What to comment on: the doc's text (body, the default), or its title, subtitle or author line.",
            "type": "string",
            "enum": [
              "body",
              "title",
              "subtitle",
              "author"
            ]
          }
        },
        "required": [
          "quote",
          "content"
        ],
        "additionalProperties": false
      },
      "CommentsAddResponse": {
        "type": "object",
        "properties": {
          "commentId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "field": {
            "type": "string",
            "enum": [
              "body",
              "title",
              "subtitle",
              "author"
            ]
          },
          "anchor": {
            "type": "string",
            "description": "The passage the comment was anchored to."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "commentId",
          "docId",
          "field",
          "anchor",
          "rev"
        ],
        "additionalProperties": false
      },
      "CommentsReplyRequest": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000,
            "description": "The reply."
          }
        },
        "required": [
          "content"
        ],
        "additionalProperties": false
      },
      "CommentsReplyResponse": {
        "type": "object",
        "properties": {
          "commentId": {
            "type": "string"
          },
          "replyId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "commentId",
          "replyId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "CommentsResolveResponse": {
        "type": "object",
        "properties": {
          "commentId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "commentId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "ChangesListResponse": {
        "type": "object",
        "properties": {
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "docId": {
                  "type": "string"
                },
                "docTitle": {
                  "type": "string"
                },
                "field": {
                  "type": "string",
                  "enum": [
                    "body",
                    "title",
                    "subtitle",
                    "author"
                  ],
                  "description": "Where the change is: the doc's body, or its title, subtitle or author line."
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "insert",
                    "delete",
                    "format",
                    "substitution",
                    "moved"
                  ]
                },
                "author": {
                  "type": "string"
                },
                "byConnect": {
                  "type": "boolean",
                  "description": "True when this app suggested it for you and can still withdraw it here; everything else is accepted or rejected in Dabble."
                },
                "createdAt": {
                  "type": "string",
                  "description": "ISO 8601."
                },
                "deleted": {
                  "type": "string",
                  "description": "The passage marked for deletion, as it still reads; empty for a pure insertion."
                },
                "inserted": {
                  "type": "string",
                  "description": "The text suggested; empty for a pure deletion."
                },
                "before": {
                  "type": "string",
                  "description": "The text just before the change."
                },
                "after": {
                  "type": "string",
                  "description": "The text just after the change."
                }
              },
              "required": [
                "id",
                "docId",
                "docTitle",
                "field",
                "type",
                "author",
                "byConnect",
                "createdAt",
                "deleted",
                "inserted",
                "before",
                "after"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "changes"
        ],
        "additionalProperties": false
      },
      "ChangesSuggestRequest": {
        "type": "object",
        "properties": {
          "quote": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "The passage the suggestion is about, quoted from manuscript_read."
          },
          "occurrence": {
            "description": "Which occurrence to use when the quote appears more than once (1-based).",
            "type": "integer",
            "minimum": 1
          },
          "text": {
            "type": "string",
            "maxLength": 5000,
            "description": "The suggested text. With replace, empty suggests deleting the passage."
          },
          "placement": {
            "description": "Where the text goes: in place of the passage (default), before it, or after it.",
            "type": "string",
            "enum": [
              "replace",
              "before",
              "after"
            ]
          },
          "field": {
            "description": "What to suggest in: the doc's text (body, the default), or its title, subtitle or author line.",
            "type": "string",
            "enum": [
              "body",
              "title",
              "subtitle",
              "author"
            ]
          }
        },
        "required": [
          "quote",
          "text"
        ],
        "additionalProperties": false
      },
      "ChangesSuggestResponse": {
        "type": "object",
        "properties": {
          "changeId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "field": {
            "type": "string",
            "enum": [
              "body",
              "title",
              "subtitle",
              "author"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "insert",
              "delete",
              "substitution"
            ]
          },
          "deleted": {
            "type": "string",
            "description": "The passage marked for deletion; empty for an insertion."
          },
          "inserted": {
            "type": "string",
            "description": "The text suggested; empty for a deletion."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "changeId",
          "docId",
          "field",
          "type",
          "deleted",
          "inserted",
          "rev"
        ],
        "additionalProperties": false
      },
      "ChangesWithdrawResponse": {
        "type": "object",
        "properties": {
          "changeId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "changeId",
          "docId",
          "rev"
        ],
        "additionalProperties": false
      },
      "GoalsGetProgressResponse": {
        "type": "object",
        "properties": {
          "total": {
            "type": "number",
            "description": "Manuscript word count now."
          },
          "goals": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "absolute",
                    "delta"
                  ]
                },
                "scope": {
                  "type": "string",
                  "description": "What the goal counts: a doc title, or \"the whole project\"."
                },
                "shared": {
                  "type": "boolean"
                },
                "start": {
                  "type": "number"
                },
                "end": {
                  "type": "number"
                },
                "current": {
                  "type": "number"
                },
                "remaining": {
                  "type": "number"
                },
                "startedAt": {
                  "description": "YYYY-MM-DD",
                  "type": "string"
                },
                "deadlineAt": {
                  "description": "YYYY-MM-DD",
                  "type": "string"
                },
                "docId": {
                  "type": "string"
                },
                "wonAt": {
                  "description": "YYYY-MM-DD",
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "type",
                "scope",
                "shared",
                "start",
                "end",
                "current",
                "remaining"
              ],
              "additionalProperties": false
            }
          },
          "daily": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "day": {
                  "type": "string",
                  "description": "YYYY-MM-DD"
                },
                "mine": {
                  "type": "number",
                  "description": "Words the author wrote that day."
                },
                "everyone": {
                  "type": "number",
                  "description": "Words everyone on the project wrote that day."
                }
              },
              "required": [
                "day",
                "mine",
                "everyone"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "total",
          "goals",
          "daily"
        ],
        "additionalProperties": false
      },
      "GoalsSetRequest": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "project",
              "all_books",
              "book",
              "chapter",
              "section"
            ],
            "description": "What the goal counts."
          },
          "docId": {
            "description": "The book, chapter, or section id from dabble_get_outline (book, chapter, section scopes).",
            "type": "string"
          },
          "target": {
            "type": "integer",
            "minimum": 1,
            "description": "Words to reach in total, or to add with countMode additional."
          },
          "countMode": {
            "type": "string",
            "enum": [
              "total",
              "additional"
            ]
          },
          "deadlineAt": {
            "description": "Deadline, YYYY-MM-DD.",
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "startedAt": {
            "description": "Start date, YYYY-MM-DD; may be in the future.",
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "name": {
            "description": "A name for the goal.",
            "type": "string",
            "maxLength": 100
          },
          "shared": {
            "description": "Make it the project's shared goal, visible to every collaborator.",
            "type": "boolean"
          },
          "goalId": {
            "description": "An existing goal id from goals_get_progress to update.",
            "type": "string"
          }
        },
        "required": [
          "scope",
          "target"
        ],
        "additionalProperties": false
      },
      "GoalsSetResponse": {
        "type": "object",
        "properties": {
          "goalId": {
            "type": "string"
          },
          "created": {
            "type": "boolean",
            "description": "True when a new goal was made rather than an existing one updated."
          },
          "goal": {
            "type": "object",
            "properties": {
              "type": {
                "description": "absolute counts total words; delta counts words added.",
                "type": "string",
                "enum": [
                  "absolute",
                  "delta"
                ]
              },
              "name": {
                "type": "string"
              },
              "userId": {
                "description": "Set on a personal goal; absent on the project’s shared goal.",
                "type": "string"
              },
              "docId": {
                "description": "The book, chapter or section the goal counts; absent for the whole project.",
                "type": "string"
              },
              "start": {
                "description": "Word count when the goal was set.",
                "type": "number"
              },
              "end": {
                "description": "Target word count.",
                "type": "number"
              },
              "countMode": {
                "type": "string",
                "enum": [
                  "total",
                  "additional"
                ]
              },
              "startedAt": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "deadlineAt": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "lastDailyWinAt": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "goalWinAt": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "earlyWordsHandled": {
                "type": "boolean"
              },
              "earlyWordsIncluded": {
                "type": "number"
              },
              "earlyWordsIncludedOn": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "archivedAt": {
                "description": "YYYY-MM-DD",
                "type": "string"
              },
              "daysOff": {
                "description": "Non-working days: a weekday (0-6) or a date (YYYY-MM-DD) → true for off, false for a working exception.",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "boolean"
                }
              },
              "savedAt": {
                "description": "ISO 8601 datetime of the last explicit save.",
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "current": {
            "type": "number",
            "description": "Words in the goal’s scope now."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "goalId",
          "created",
          "goal",
          "current",
          "rev"
        ],
        "additionalProperties": false
      },
      "GoalsArchiveRequest": {
        "type": "object",
        "properties": {
          "restore": {
            "description": "Restore an archived goal instead of archiving.",
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "GoalsArchiveResponse": {
        "type": "object",
        "properties": {
          "goalId": {
            "type": "string"
          },
          "archived": {
            "type": "boolean"
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "goalId",
          "archived",
          "rev"
        ],
        "additionalProperties": false
      },
      "HistoryListVersionsResponse": {
        "type": "object",
        "properties": {
          "rev": {
            "type": "number",
            "description": "The project’s revision now."
          },
          "versions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "label": {
                  "type": "string",
                  "description": "The version as the history panel names it."
                },
                "name": {
                  "description": "The name the author gave a saved version.",
                  "type": "string"
                },
                "startedAt": {
                  "type": "string",
                  "description": "ISO 8601."
                },
                "endedAt": {
                  "type": "string",
                  "description": "ISO 8601."
                },
                "startRev": {
                  "type": "number"
                },
                "endRev": {
                  "type": "number"
                },
                "origin": {
                  "type": "string"
                },
                "authors": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Who wrote in this version, most prolific first."
                },
                "manual": {
                  "type": "boolean",
                  "description": "Sealed by hand rather than by the autosave clock."
                },
                "beforeRestored": {
                  "type": "boolean",
                  "description": "The checkpoint sealed just before a restore."
                }
              },
              "required": [
                "id",
                "label",
                "startedAt",
                "endedAt",
                "startRev",
                "endRev",
                "authors",
                "manual",
                "beforeRestored"
              ],
              "additionalProperties": false
            }
          },
          "nextBefore": {
            "description": "Pass as before to page further back; null at the end.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "rev",
          "versions",
          "nextBefore"
        ],
        "additionalProperties": false
      },
      "HistoryReadDocResponse": {
        "type": "object",
        "properties": {
          "versionId": {
            "type": "string"
          },
          "docId": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "words": {
            "type": "number"
          },
          "existsNow": {
            "type": "boolean",
            "description": "Whether the doc is still live in the project."
          },
          "text": {
            "type": "string",
            "description": "This page of the text."
          },
          "offset": {
            "type": "number",
            "description": "Character offset this page starts at."
          },
          "nextOffset": {
            "description": "Offset to continue from, or null when this page is the last.",
            "type": [
              "number",
              "null"
            ]
          },
          "totalLength": {
            "type": "number",
            "description": "Length of the whole text in characters."
          },
          "format": {
            "type": "string",
            "enum": [
              "markdown",
              "text"
            ]
          }
        },
        "required": [
          "versionId",
          "docId",
          "type",
          "title",
          "words",
          "existsNow",
          "text",
          "offset",
          "nextOffset",
          "totalLength",
          "format"
        ],
        "additionalProperties": false
      },
      "HistorySearchResponse": {
        "type": "object",
        "properties": {
          "presentNow": {
            "type": "boolean",
            "description": "Whether the passage is still in the live project."
          },
          "found": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "docId": {
                    "type": "string"
                  },
                  "docTitle": {
                    "type": "string"
                  },
                  "docType": {
                    "type": "string"
                  },
                  "count": {
                    "type": "number",
                    "description": "Occurrences of the passage in the doc."
                  },
                  "snippet": {
                    "type": "string"
                  },
                  "version": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string",
                        "description": "The version as the history panel names it."
                      },
                      "name": {
                        "description": "The name the author gave a saved version.",
                        "type": "string"
                      },
                      "startedAt": {
                        "type": "string",
                        "description": "ISO 8601."
                      },
                      "endedAt": {
                        "type": "string",
                        "description": "ISO 8601."
                      },
                      "startRev": {
                        "type": "number"
                      },
                      "endRev": {
                        "type": "number"
                      },
                      "origin": {
                        "type": "string"
                      },
                      "authors": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Who wrote in this version, most prolific first."
                      },
                      "manual": {
                        "type": "boolean",
                        "description": "Sealed by hand rather than by the autosave clock."
                      },
                      "beforeRestored": {
                        "type": "boolean",
                        "description": "The checkpoint sealed just before a restore."
                      }
                    },
                    "required": [
                      "id",
                      "label",
                      "startedAt",
                      "endedAt",
                      "startRev",
                      "endRev",
                      "authors",
                      "manual",
                      "beforeRestored"
                    ],
                    "additionalProperties": false
                  }
                },
                "required": [
                  "docId",
                  "docTitle",
                  "docType",
                  "count",
                  "snippet",
                  "version"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The most recent version that still holds the passage."
          },
          "goneBy": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "label": {
                    "type": "string",
                    "description": "The version as the history panel names it."
                  },
                  "name": {
                    "description": "The name the author gave a saved version.",
                    "type": "string"
                  },
                  "startedAt": {
                    "type": "string",
                    "description": "ISO 8601."
                  },
                  "endedAt": {
                    "type": "string",
                    "description": "ISO 8601."
                  },
                  "startRev": {
                    "type": "number"
                  },
                  "endRev": {
                    "type": "number"
                  },
                  "origin": {
                    "type": "string"
                  },
                  "authors": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Who wrote in this version, most prolific first."
                  },
                  "manual": {
                    "type": "boolean",
                    "description": "Sealed by hand rather than by the autosave clock."
                  },
                  "beforeRestored": {
                    "type": "boolean",
                    "description": "The checkpoint sealed just before a restore."
                  }
                },
                "required": [
                  "id",
                  "label",
                  "startedAt",
                  "endedAt",
                  "startRev",
                  "endRev",
                  "authors",
                  "manual",
                  "beforeRestored"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The earliest version checked that no longer holds it."
          },
          "checked": {
            "type": "number"
          },
          "skipped": {
            "type": "number",
            "description": "Versions that could not be read and were stepped over."
          },
          "nextBefore": {
            "description": "Pass as before to keep searching back; null at the end.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "presentNow",
          "found",
          "goneBy",
          "checked",
          "skipped",
          "nextBefore"
        ],
        "additionalProperties": false
      },
      "HistoryBringForwardResponse": {
        "type": "object",
        "properties": {
          "docId": {
            "type": "string",
            "description": "The copy in the Restored section."
          },
          "title": {
            "type": "string"
          },
          "docs": {
            "type": "number",
            "description": "Documents copied, the copy and its descendants."
          },
          "words": {
            "type": "number"
          },
          "stripped": {
            "type": "object",
            "properties": {
              "changes": {
                "type": "number"
              },
              "comments": {
                "type": "number"
              },
              "embeds": {
                "type": "number"
              },
              "formats": {
                "type": "number"
              },
              "notes": {
                "type": "number"
              }
            },
            "required": [
              "changes",
              "comments",
              "embeds",
              "formats",
              "notes"
            ],
            "additionalProperties": false
          },
          "createdSection": {
            "type": "boolean",
            "description": "True when the Restored section was created for this copy."
          },
          "rev": {
            "description": "The project revision after the change, or null when the sync service did not report one.",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "docId",
          "title",
          "docs",
          "words",
          "stripped",
          "createdSection",
          "rev"
        ],
        "additionalProperties": false
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is malformed, or an argument failed validation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No credential, or one that is invalid, expired, or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The credential lacks the scope, the account lacks a subscription with Connect or the feature, or your role on the project does not allow this.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such project, document, or endpoint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "The change is too large for Dabble to store in one piece.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "A rate limit was hit; wait for the Retry-After seconds.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "Dabble Connect hit an unexpected error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadGateway": {
        "description": "The Dabble sync service answered with an error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Dabble is temporarily unavailable; try again shortly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "oauth2": []
    },
    {
      "apiKey": []
    }
  ]
}