{
  "openapi": "3.1.0",
  "info": {
    "title": "HeyBMO API",
    "version": "1",
    "description": "Every HeyBMO operation as one POST endpoint. Docs: https://heybmo.com/developers/api"
  },
  "servers": [{ "url": "https://app.heybmo.com" }],
  "security": [{ "bearer": [] }],
  "components": {
    "securitySchemes": { "bearer": { "type": "http", "scheme": "bearer" } },
    "responses": {
      "Error": {
        "description": "An error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": ["code", "message", "requestId"],
              "properties": {
                "code": { "type": "string" },
                "message": { "type": "string" },
                "requestId": { "type": "string" },
                "hint": { "type": "string" },
                "reason": { "type": "string" },
                "retryAfterSeconds": { "type": "integer" }
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/ops/account.spaces": {
      "post": {
        "operationId": "account.spaces",
        "summary": "List your spaces",
        "description": "List the spaces this person can use (their personal space and any shared ones), with the one this call runs in marked current.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "spaces": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["personal", "shared"] },
                              "name": { "type": "string" },
                              "current": { "type": "boolean" }
                            },
                            "required": ["id", "kind", "name", "current"]
                          }
                        }
                      },
                      "required": ["spaces"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.timeZone": {
      "post": {
        "operationId": "account.timeZone",
        "summary": "Get your time zone",
        "description": "Get this person’s time zone. Reminders and other scheduled work run at wall-clock times in it.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "timeZone": {
                          "type": "string",
                          "description": "IANA time zone name, e.g. Europe/London"
                        }
                      },
                      "required": ["timeZone"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.changeTimeZone": {
      "post": {
        "operationId": "account.changeTimeZone",
        "summary": "Change your time zone",
        "description": "Change this person’s time zone (an IANA name like Europe/London or Asia/Tokyo), e.g. after they move or travel. Their scheduled work moves with them and keeps its wall-clock times.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": { "timeZone": { "type": "string", "maxLength": 64 } },
                    "required": ["timeZone"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "timeZone": "Europe/London" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "timeZone": {
                          "type": "string",
                          "description": "IANA time zone name, e.g. Europe/London"
                        }
                      },
                      "required": ["timeZone"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.currency": {
      "post": {
        "operationId": "account.currency",
        "summary": "Get your home currency",
        "description": "Get this person’s home currency: money they track in other currencies is totalled in it. Null until it is set.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "currency": {
                          "description": "ISO 4217 code money totals are shown in, e.g. MAD; null until it is set",
                          "type": ["string", "null"]
                        }
                      },
                      "required": ["currency"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.changeCurrency": {
      "post": {
        "operationId": "account.changeCurrency",
        "summary": "Change your home currency",
        "description": "Change this person’s home currency (a code like MAD, USD or EUR), e.g. after they move. Saved amounts keep their own currency; totals are worked out again in the new one with each day’s stored rate.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "currency": {
                        "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                        "type": "string"
                      }
                    },
                    "required": ["currency"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "currency": "MAD" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "currency": {
                          "description": "ISO 4217 code money totals are shown in, e.g. MAD; null until it is set",
                          "type": ["string", "null"]
                        }
                      },
                      "required": ["currency"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.profile": {
      "post": {
        "operationId": "account.profile",
        "summary": "Get your profile",
        "description": "Get this person’s name, the avatar they designed (null until they do) and the first day of their week.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "name": { "type": "string" },
                        "look": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "hue": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 360,
                                  "description": "Colour, 0 to 360 degrees round the colour wheel"
                                },
                                "tone": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Skin tone, 0 (lightest) to 1 (darkest)"
                                },
                                "shape": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Face shape, 0 to 1"
                                }
                              },
                              "required": ["hue", "tone", "shape"],
                              "description": "The avatar the person designed"
                            },
                            { "type": "null" }
                          ],
                          "description": "Null until the person designs their avatar"
                        },
                        "weekStart": {
                          "type": "string",
                          "enum": ["monday", "sunday"],
                          "description": "The first day of the week in calendars"
                        }
                      },
                      "required": ["name", "look", "weekStart"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/account.changeProfile": {
      "post": {
        "operationId": "account.changeProfile",
        "summary": "Change your profile",
        "description": "Change this person’s name, avatar or the first day of their week. Only what is given changes. Their email and sign-in details are changed in HeyBMO’s settings, not here.",
        "tags": ["account"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "description": "The name HeyBMO calls them",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 120
                      },
                      "look": {
                        "type": "object",
                        "properties": {
                          "hue": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 360,
                            "description": "Colour, 0 to 360 degrees round the colour wheel"
                          },
                          "tone": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1,
                            "description": "Skin tone, 0 (lightest) to 1 (darkest)"
                          },
                          "shape": {
                            "type": "number",
                            "minimum": 0,
                            "maximum": 1,
                            "description": "Face shape, 0 to 1"
                          }
                        },
                        "required": ["hue", "tone", "shape"],
                        "description": "The avatar the person designed"
                      },
                      "weekStart": {
                        "type": "string",
                        "enum": ["monday", "sunday"],
                        "description": "The first day of the week in calendars"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "name": "Taha" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "name": { "type": "string" },
                        "look": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "hue": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 360,
                                  "description": "Colour, 0 to 360 degrees round the colour wheel"
                                },
                                "tone": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Skin tone, 0 (lightest) to 1 (darkest)"
                                },
                                "shape": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 1,
                                  "description": "Face shape, 0 to 1"
                                }
                              },
                              "required": ["hue", "tone", "shape"],
                              "description": "The avatar the person designed"
                            },
                            { "type": "null" }
                          ],
                          "description": "Null until the person designs their avatar"
                        },
                        "weekStart": {
                          "type": "string",
                          "enum": ["monday", "sunday"],
                          "description": "The first day of the week in calendars"
                        }
                      },
                      "required": ["name", "look", "weekStart"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.list": {
      "post": {
        "operationId": "inbox.list",
        "summary": "Read the inbox",
        "description": "List the person’s HeyBMO inbox, newest first: reminders that went off, automation messages and notices from HeyBMO, with how many are unread. Each entry says who sent it and which records it is about, and how each stands now, so it can be acted on (mark a reminder done, record a payback): a reminders.firing whose facts say done or whose state is not live needs nothing more. Reading does not mark anything read; inbox.markRead does.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "unread": {
                        "default": false,
                        "description": "Only entries not read yet",
                        "type": "boolean"
                      },
                      "from": {
                        "description": "Only from this sender: a feature id (reminders), automations, or heybmo",
                        "type": "string"
                      },
                      "limit": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 },
                      "cursor": {
                        "description": "nextCursor from the previous page",
                        "type": "string"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string" },
                              "from": {
                                "type": "string",
                                "description": "Who sent it: a feature (reminders), automations, or heybmo"
                              },
                              "title": { "type": "string" },
                              "body": { "type": "string" },
                              "link": { "type": "string" },
                              "details": {
                                "description": "The same message as labelled facts (and its picture), when its kind has them",
                                "type": "object",
                                "properties": {
                                  "visual": {
                                    "oneOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "kind": { "type": "string", "const": "time" },
                                          "time": { "type": "string" },
                                          "date": { "type": "string", "format": "date" }
                                        },
                                        "required": ["kind", "time", "date"],
                                        "description": "A time of day, e.g. a reminder going off"
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "kind": { "type": "string", "const": "progress" },
                                          "percent": {
                                            "type": "integer",
                                            "minimum": 0,
                                            "maximum": 9007199254740991
                                          },
                                          "label": {
                                            "type": "string",
                                            "description": "What the share means, e.g. \"MAD 32.12 over\""
                                          }
                                        },
                                        "required": ["kind", "percent", "label"],
                                        "description": "A share used, e.g. a budget at 108%"
                                      }
                                    ]
                                  },
                                  "facts": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "label": { "type": "string" },
                                        "value": { "type": "string" }
                                      },
                                      "required": ["label", "value"]
                                    }
                                  },
                                  "links": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "label": { "type": "string" },
                                        "to": {
                                          "type": "string",
                                          "description": "A path in the HeyBMO app"
                                        }
                                      },
                                      "required": ["label", "to"]
                                    }
                                  }
                                },
                                "required": ["facts", "links"]
                              },
                              "about": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "kind": {
                                      "type": "string",
                                      "description": "A record kind, e.g. reminders.firing, debts.debt"
                                    },
                                    "id": { "type": "string" },
                                    "state": {
                                      "description": "Now: live, in its feature's trash, or deleted (or its feature switched off). Left out for kinds that are not looked up",
                                      "type": "string",
                                      "enum": ["live", "trash", "deleted"]
                                    },
                                    "facts": {
                                      "description": "A reminders.firing: missed (done and snooze apply), snoozed (until when) or done. A list: items left of all. A debt or expense: its money",
                                      "oneOf": [
                                        {
                                          "type": "object",
                                          "properties": {
                                            "kind": { "type": "string", "const": "progress" },
                                            "left": {
                                              "type": "integer",
                                              "minimum": -9007199254740991,
                                              "maximum": 9007199254740991
                                            },
                                            "total": {
                                              "type": "integer",
                                              "minimum": -9007199254740991,
                                              "maximum": 9007199254740991
                                            }
                                          },
                                          "required": ["kind", "left", "total"]
                                        },
                                        {
                                          "type": "object",
                                          "properties": {
                                            "kind": { "type": "string", "const": "money" },
                                            "way": { "type": "string", "enum": ["in", "out"] },
                                            "amount": { "type": "number" },
                                            "currency": { "type": "string" }
                                          },
                                          "required": ["kind", "way", "amount", "currency"]
                                        },
                                        {
                                          "type": "object",
                                          "properties": {
                                            "kind": { "type": "string", "const": "firing" },
                                            "state": {
                                              "type": "string",
                                              "enum": ["missed", "snoozed", "done"]
                                            },
                                            "snoozedUntil": {
                                              "anyOf": [
                                                { "type": "string", "format": "date-time" },
                                                { "type": "null" }
                                              ],
                                              "description": "When a snoozed one comes back"
                                            }
                                          },
                                          "required": ["kind", "state", "snoozedUntil"]
                                        }
                                      ]
                                    }
                                  },
                                  "required": ["kind", "id"]
                                },
                                "description": "The records it is about, most specific first; act on them with that feature’s operations"
                              },
                              "read": { "type": "boolean" },
                              "createdAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "from",
                              "title",
                              "body",
                              "about",
                              "read",
                              "createdAt"
                            ]
                          }
                        },
                        "unread": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
                        "total": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991,
                          "description": "How many entries the filter matches, across every page"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["items", "unread", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.markRead": {
      "post": {
        "operationId": "inbox.markRead",
        "summary": "Mark inbox entries read",
        "description": "Mark inbox entries read, by id, or every unread one with all: true. Marking read changes nothing else: a reminder stays not done until reminders.done.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "ids": {
                        "description": "Entries from inbox.list",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": { "type": "string", "format": "uuid" }
                      },
                      "all": {
                        "default": false,
                        "description": "Every unread entry",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "ids": ["01a19baf-5f80-7b83-9fd5-667bd5562b12"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "marked": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 },
                        "unread": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }
                      },
                      "required": ["marked", "unread"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.settings": {
      "post": {
        "operationId": "inbox.settings",
        "summary": "Read notification settings",
        "description": "Read how this person is told things: the channels every message goes to by default, each group’s channels (and whether it follows the default), quiet hours, and the morning email. The inbox always gets every message. One item’s own channels (a reminder’s delivery) win over its group, which wins over the default.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "defaults": {
                          "type": "array",
                          "items": { "type": "string", "enum": ["email"] },
                          "description": "Channels every message goes to besides the inbox, unless its group or one item has its own set"
                        },
                        "groups": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "group": {
                                "type": "string",
                                "enum": ["reminders", "budget", "automations", "heybmo"]
                              },
                              "follows": {
                                "type": "boolean",
                                "description": "true while the group follows the default channels (and reminders pop up)"
                              },
                              "channels": {
                                "type": "array",
                                "items": { "type": "string", "enum": ["email", "push", "desktop"] },
                                "description": "Where its messages go besides the inbox: email, push (a browser pop-up) and/or desktop (the HeyBMO app on the computer)"
                              }
                            },
                            "required": ["group", "follows", "channels"]
                          }
                        },
                        "quiet": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "from": { "type": "string" },
                                "to": { "type": "string" }
                              },
                              "required": ["from", "to"]
                            },
                            { "type": "null" }
                          ],
                          "description": "In these hours (the person’s time zone) only the inbox gets new messages"
                        },
                        "dailyEmail": {
                          "type": "boolean",
                          "description": "One email each morning at 07:30 instead of single emails"
                        },
                        "sound": {
                          "type": "boolean",
                          "description": "A short sound when a new message arrives in an open app; quiet hours silence it"
                        }
                      },
                      "required": ["defaults", "groups", "quiet", "dailyEmail", "sound"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.changeSettings": {
      "post": {
        "operationId": "inbox.changeSettings",
        "summary": "Change notification settings",
        "description": "Change how this person is told things, only when they ask. Set the default channels (email or none, besides the inbox), a group’s own channels (email, push and/or desktop, several at once; follow: true puts it back on the default), quiet hours (null turns them off), or the morning email. Only what is given changes.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "groups": {
                        "maxItems": 4,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "group": {
                              "type": "string",
                              "enum": ["reminders", "budget", "automations", "heybmo"]
                            },
                            "follow": {
                              "description": "Back to following the default",
                              "type": "boolean",
                              "const": true
                            },
                            "channels": {
                              "description": "Its own channels besides the inbox; [] is the inbox only",
                              "maxItems": 3,
                              "type": "array",
                              "items": { "type": "string", "enum": ["email", "push", "desktop"] }
                            },
                            "route": {
                              "description": "Older single choice; use channels",
                              "type": "string",
                              "enum": ["default", "inbox", "email"]
                            },
                            "push": {
                              "description": "Older pop-up switch; use channels",
                              "type": "boolean"
                            }
                          },
                          "required": ["group"]
                        }
                      },
                      "quiet": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "from": { "type": "string" },
                              "to": { "type": "string" }
                            },
                            "required": ["from", "to"]
                          },
                          { "type": "null" }
                        ]
                      },
                      "dailyEmail": { "type": "boolean" },
                      "sound": { "type": "boolean" },
                      "defaults": {
                        "description": "The default channels besides the inbox; [] is the inbox only",
                        "maxItems": 1,
                        "type": "array",
                        "items": { "type": "string", "enum": ["email"] }
                      },
                      "defaultRoute": {
                        "description": "Older single choice; use defaults",
                        "type": "string",
                        "enum": ["inbox", "email"]
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "defaults": ["email"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "defaults": {
                          "type": "array",
                          "items": { "type": "string", "enum": ["email"] },
                          "description": "Channels every message goes to besides the inbox, unless its group or one item has its own set"
                        },
                        "groups": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "group": {
                                "type": "string",
                                "enum": ["reminders", "budget", "automations", "heybmo"]
                              },
                              "follows": {
                                "type": "boolean",
                                "description": "true while the group follows the default channels (and reminders pop up)"
                              },
                              "channels": {
                                "type": "array",
                                "items": { "type": "string", "enum": ["email", "push", "desktop"] },
                                "description": "Where its messages go besides the inbox: email, push (a browser pop-up) and/or desktop (the HeyBMO app on the computer)"
                              }
                            },
                            "required": ["group", "follows", "channels"]
                          }
                        },
                        "quiet": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "from": { "type": "string" },
                                "to": { "type": "string" }
                              },
                              "required": ["from", "to"]
                            },
                            { "type": "null" }
                          ],
                          "description": "In these hours (the person’s time zone) only the inbox gets new messages"
                        },
                        "dailyEmail": {
                          "type": "boolean",
                          "description": "One email each morning at 07:30 instead of single emails"
                        },
                        "sound": {
                          "type": "boolean",
                          "description": "A short sound when a new message arrives in an open app; quiet hours silence it"
                        }
                      },
                      "required": ["defaults", "groups", "quiet", "dailyEmail", "sound"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.devices": {
      "post": {
        "operationId": "inbox.devices",
        "summary": "List devices that show pop-ups",
        "description": "List the browsers and devices where this person allowed HeyBMO pop-ups, and the key a browser needs to allow them (null when pop-ups are off on this server).",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "publicKey": { "type": ["string", "null"] },
                        "devices": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "label": { "type": "string" },
                              "endpoint": {
                                "type": "string",
                                "description": "The browser’s push address, to recognise this browser"
                              },
                              "addedAt": { "type": "string", "format": "date-time" },
                              "lastUsedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              }
                            },
                            "required": ["id", "label", "endpoint", "addedAt", "lastUsedAt"]
                          }
                        }
                      },
                      "required": ["publicKey", "devices"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.addDevice": {
      "post": {
        "operationId": "inbox.addDevice",
        "summary": "Allow pop-ups on this browser",
        "description": "Save the browser the person is using as one that shows HeyBMO pop-ups (its Web Push subscription). Done by HeyBMO in the browser after the person allows notifications. A person keeps up to 20; adding one more forgets the one used longest ago.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "endpoint": { "type": "string", "maxLength": 2048, "format": "uri" },
                      "p256dh": { "type": "string" },
                      "auth": { "type": "string" },
                      "label": { "type": "string", "minLength": 1, "maxLength": 120 }
                    },
                    "required": ["endpoint", "p256dh", "auth", "label"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "endpoint": "https://fcm.googleapis.com/fcm/send/abc123",
                  "p256dh": "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM",
                  "auth": "tBHItJI5svbpez7KI4CCXg",
                  "label": "Chrome on Windows"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "device": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "label": { "type": "string" },
                            "endpoint": {
                              "type": "string",
                              "description": "The browser’s push address, to recognise this browser"
                            },
                            "addedAt": { "type": "string", "format": "date-time" },
                            "lastUsedAt": {
                              "anyOf": [
                                { "type": "string", "format": "date-time" },
                                { "type": "null" }
                              ]
                            }
                          },
                          "required": ["id", "label", "endpoint", "addedAt", "lastUsedAt"]
                        }
                      },
                      "required": ["device"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.removeDevice": {
      "post": {
        "operationId": "inbox.removeDevice",
        "summary": "Stop pop-ups on a device",
        "description": "Stop HeyBMO pop-ups on one browser or device (from inbox.devices). Its inbox and emails are not affected; pop-ups can be allowed again from that browser.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "id": { "type": "string", "format": "uuid" },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["id"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "id": "01a1b0b6-94af-77a1-b13f-0fb0e1b38487" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": { "removed": { "type": "boolean" } },
                      "required": ["removed"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/inbox.testPopup": {
      "post": {
        "operationId": "inbox.testPopup",
        "summary": "Send a test pop-up",
        "description": "Send one test pop-up to every device where the person allowed pop-ups, so they can see it works. Quiet hours do not stop it.",
        "tags": ["inbox"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "devices": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["devices"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/home.layout": {
      "post": {
        "operationId": "home.layout",
        "summary": "Read the Today page layout",
        "description": "The widgets on the person’s Today page in HeyBMO, where they sit on its 12-column grid and how big, plus the widgets available from the features switched on. Until the person arranges it, a starting layout is returned (saved: false).",
        "tags": ["home"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "widgets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "widget": {
                                "type": "string",
                                "description": "A widget id from available"
                              },
                              "x": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 11,
                                "description": "Column, 0 to 11"
                              },
                              "y": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 2999,
                                "description": "Row, from 0 at the top"
                              },
                              "w": {
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 12,
                                "description": "Width in columns"
                              },
                              "h": {
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 80,
                                "description": "Height in rows"
                              },
                              "settings": {
                                "default": {},
                                "description": "The widget’s own choices",
                                "type": "object",
                                "propertyNames": { "type": "string" }
                              }
                            },
                            "required": ["widget", "x", "y", "w", "h", "settings"]
                          }
                        },
                        "available": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "feature": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" },
                              "minSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              },
                              "maxSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              },
                              "defaultSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              }
                            },
                            "required": [
                              "id",
                              "feature",
                              "title",
                              "description",
                              "minSize",
                              "maxSize",
                              "defaultSize"
                            ]
                          },
                          "description": "Widgets of the features switched on here"
                        },
                        "saved": {
                          "type": "boolean",
                          "description": "False while the person has not arranged Today yet"
                        }
                      },
                      "required": ["widgets", "available", "saved"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/home.saveLayout": {
      "post": {
        "operationId": "home.saveLayout",
        "summary": "Arrange the Today page",
        "description": "Save the whole Today page: every widget to show, with its place and size (widgets left out are removed). Up to 40 widgets, each from home.layout's available list, at a size it allows. Widgets of switched-off features are kept as they were.",
        "tags": ["home"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "widgets": {
                        "maxItems": 40,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "widget": {
                              "type": "string",
                              "description": "A widget id from available"
                            },
                            "x": {
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 11,
                              "description": "Column, 0 to 11"
                            },
                            "y": {
                              "type": "integer",
                              "minimum": 0,
                              "maximum": 2999,
                              "description": "Row, from 0 at the top"
                            },
                            "w": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 12,
                              "description": "Width in columns"
                            },
                            "h": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 80,
                              "description": "Height in rows"
                            },
                            "settings": {
                              "default": {},
                              "description": "The widget’s own choices",
                              "type": "object",
                              "propertyNames": { "type": "string" }
                            }
                          },
                          "required": ["widget", "x", "y", "w", "h"]
                        }
                      }
                    },
                    "required": ["widgets"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "widgets": [{ "widget": "reminders.today", "x": 0, "y": 0, "w": 6, "h": 3 }]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "widgets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "widget": {
                                "type": "string",
                                "description": "A widget id from available"
                              },
                              "x": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 11,
                                "description": "Column, 0 to 11"
                              },
                              "y": {
                                "type": "integer",
                                "minimum": 0,
                                "maximum": 2999,
                                "description": "Row, from 0 at the top"
                              },
                              "w": {
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 12,
                                "description": "Width in columns"
                              },
                              "h": {
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 80,
                                "description": "Height in rows"
                              },
                              "settings": {
                                "default": {},
                                "description": "The widget’s own choices",
                                "type": "object",
                                "propertyNames": { "type": "string" }
                              }
                            },
                            "required": ["widget", "x", "y", "w", "h", "settings"]
                          }
                        },
                        "available": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "feature": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" },
                              "minSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              },
                              "maxSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              },
                              "defaultSize": {
                                "type": "array",
                                "prefixItems": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  }
                                ],
                                "items": false,
                                "minItems": 2,
                                "maxItems": 2
                              }
                            },
                            "required": [
                              "id",
                              "feature",
                              "title",
                              "description",
                              "minSize",
                              "maxSize",
                              "defaultSize"
                            ]
                          },
                          "description": "Widgets of the features switched on here"
                        },
                        "saved": {
                          "type": "boolean",
                          "description": "False while the person has not arranged Today yet"
                        }
                      },
                      "required": ["widgets", "available", "saved"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/marketplace.list": {
      "post": {
        "operationId": "marketplace.list",
        "summary": "List features you can switch on",
        "description": "List the features this person can switch on in the current space (notes, expenses, lists...), with what each does, what it requires and whether it is on.",
        "tags": ["marketplace"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "features": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "name": { "type": "string" },
                              "description": { "type": "string" },
                              "category": {
                                "type": "string",
                                "enum": ["money", "notes", "organize", "documents", "other"]
                              },
                              "status": { "type": "string", "enum": ["beta", "public"] },
                              "plan": { "type": ["string", "null"] },
                              "requires": { "type": "array", "items": { "type": "string" } },
                              "enabled": { "type": "boolean" },
                              "tagline": {
                                "description": "One line under its name in the store",
                                "type": ["string", "null"]
                              },
                              "updated": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ],
                                "description": "The day it last changed"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "description",
                              "category",
                              "status",
                              "plan",
                              "requires",
                              "enabled",
                              "tagline",
                              "updated"
                            ]
                          }
                        }
                      },
                      "required": ["features"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/marketplace.get": {
      "post": {
        "operationId": "marketplace.get",
        "summary": "Read a feature’s store page",
        "description": "Read what the store says about one feature before switching it on. It gives what the feature does, what to ask an AI app, the data it keeps, its limits and what changed lately. It also names the features it works with, its Today widgets and events, and what switching it on or off would also change.",
        "tags": ["marketplace"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "feature": {
                        "type": "string",
                        "description": "A feature id from marketplace.list, e.g. debts"
                      }
                    },
                    "required": ["feature"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "feature": "debts" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "category": {
                          "type": "string",
                          "enum": ["money", "notes", "organize", "documents", "other"]
                        },
                        "status": { "type": "string", "enum": ["beta", "public"] },
                        "plan": {
                          "description": "Its plan; null while it is free",
                          "type": ["string", "null"]
                        },
                        "enabled": { "type": "boolean" },
                        "alsoSwitchesOn": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Features switching it on also switches on (not on yet)"
                        },
                        "neededBy": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Enabled features that need it (block switching off)"
                        },
                        "listing": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "tagline": { "type": "string" },
                                "pitch": { "type": "string" },
                                "headline": { "type": "string" },
                                "moments": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "kind": {
                                        "type": "string",
                                        "enum": ["person", "ai", "alert"]
                                      },
                                      "title": { "type": "string" },
                                      "detail": { "type": "string" }
                                    },
                                    "required": ["kind", "title", "detail"]
                                  }
                                },
                                "highlights": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "title": { "type": "string" },
                                      "body": { "type": "string" }
                                    },
                                    "required": ["title", "body"]
                                  }
                                },
                                "conversation": {
                                  "type": "array",
                                  "items": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": { "you": { "type": "string" } },
                                        "required": ["you"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "did": { "type": "string" },
                                          "detail": { "type": "string" }
                                        },
                                        "required": ["did", "detail"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": { "ai": { "type": "string" } },
                                        "required": ["ai"]
                                      }
                                    ]
                                  },
                                  "description": "One conversation in an AI app: what the person says, what HeyBMO did, the answer"
                                },
                                "data": {
                                  "type": "array",
                                  "items": { "type": "string" },
                                  "description": "What it keeps about the person"
                                },
                                "limits": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "label": { "type": "string" },
                                      "value": {
                                        "type": "integer",
                                        "minimum": -9007199254740991,
                                        "maximum": 9007199254740991
                                      }
                                    },
                                    "required": ["label", "value"]
                                  }
                                },
                                "changes": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "day": { "type": "string", "format": "date" },
                                      "text": { "type": "string" }
                                    },
                                    "required": ["day", "text"]
                                  },
                                  "description": "Newest first"
                                },
                                "worksWith": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "feature": { "type": "string" },
                                      "name": { "type": "string" },
                                      "how": { "type": "string" }
                                    },
                                    "required": ["feature", "name", "how"]
                                  }
                                }
                              },
                              "required": [
                                "tagline",
                                "pitch",
                                "headline",
                                "moments",
                                "highlights",
                                "conversation",
                                "data",
                                "limits",
                                "changes",
                                "worksWith"
                              ]
                            },
                            { "type": "null" }
                          ]
                        },
                        "widgets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" }
                            },
                            "required": ["id", "title", "description"]
                          }
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" }
                            },
                            "required": ["id", "title", "description"]
                          },
                          "description": "What automations can react to in it"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "category",
                        "status",
                        "plan",
                        "enabled",
                        "alsoSwitchesOn",
                        "neededBy",
                        "listing",
                        "widgets",
                        "events"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/marketplace.enable": {
      "post": {
        "operationId": "marketplace.enable",
        "summary": "Switch a feature on",
        "description": "Switch a feature on in the current space, together with the features it requires. A free feature: when the person asks for something it does, switch it on without asking first, then tell them you did. A feature with a plan is never switched on without the person: the call then switches nothing on and returns askFirst; tell them which features need a plan and which plan, and call again with approved: true only once they say yes. Only owners of the space can do this.",
        "tags": ["marketplace"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "feature": {
                        "type": "string",
                        "description": "A feature id from marketplace_list, e.g. notes"
                      },
                      "approved": {
                        "description": "true only after the person said yes to a feature with a plan (one listed in askFirst). Never set it on your own.",
                        "type": "boolean"
                      }
                    },
                    "required": ["feature"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "feature": "notes" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "enabled": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Features switched on by this call"
                        },
                        "askFirst": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "feature": { "type": "string" },
                              "plan": { "type": "string" }
                            },
                            "required": ["feature", "plan"]
                          },
                          "description": "Features with a plan waiting for the person’s yes; when not empty, nothing was switched on"
                        },
                        "next": { "type": "string", "description": "What to do next" }
                      },
                      "required": ["enabled", "askFirst", "next"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/marketplace.disable": {
      "post": {
        "operationId": "marketplace.disable",
        "summary": "Switch a feature off",
        "description": "Switch a feature off in the current space. Its data is hidden, not deleted, and comes back when it is switched on again. Refused while another enabled feature needs it.",
        "tags": ["marketplace"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "feature": {
                        "type": "string",
                        "description": "A feature id from marketplace_list, e.g. notes"
                      }
                    },
                    "required": ["feature"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "feature": "notes" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "disabled": { "type": "boolean" },
                        "blockedBy": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Enabled features that need it; switch them off first"
                        }
                      },
                      "required": ["disabled", "blockedBy"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.create": {
      "post": {
        "operationId": "notes.create",
        "summary": "Create a note",
        "description": "Create a note: a title and a Markdown body, optionally in a folder, with tags and a colour.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "title": { "type": "string", "minLength": 1, "maxLength": 200 },
                      "body": {
                        "default": "",
                        "description": "Markdown, up to 100 KB",
                        "type": "string"
                      },
                      "folderId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A folder id (from notes.folders)"
                      },
                      "tags": {
                        "maxItems": 50,
                        "type": "array",
                        "items": { "type": "string", "maxLength": 100 },
                        "description": "Labels, e.g. [\"work\", \"home\"]. Stored lower-case."
                      },
                      "pinned": { "description": "Keep it at the top of lists", "type": "boolean" },
                      "color": {
                        "type": "string",
                        "enum": ["lavender", "sky", "apricot", "lime"],
                        "description": "A colour that makes the note stand out on the board"
                      }
                    },
                    "required": ["title"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "title": "Groceries", "body": "- milk\n- eggs", "tags": ["shopping"] }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.get": {
      "post": {
        "operationId": "notes.get",
        "summary": "Read a note",
        "description": "Read one note in full: body (Markdown), tags, folder, revision, attachments (with short-lived links to view them).",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      }
                    },
                    "required": ["noteId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.list": {
      "post": {
        "operationId": "notes.list",
        "summary": "List notes",
        "description": "List notes, pinned first, then most recently changed (order changed: most recently changed first, pinned or not), with a short preview of each and how many match. Filter by folder, tag, pinned or archived. Archived notes are left out unless archived is true. Pass nextCursor back as cursor for the next page.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "folderId": {
                        "description": "Only notes in this folder; null for notes at the top level",
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "description": "A folder id (from notes.folders)"
                          },
                          { "type": "null" }
                        ]
                      },
                      "tag": {
                        "description": "Only notes with this tag",
                        "type": "string",
                        "maxLength": 100
                      },
                      "pinned": {
                        "description": "Only pinned (true) or only unpinned (false) notes",
                        "type": "boolean"
                      },
                      "archived": {
                        "default": false,
                        "description": "true lists the archive instead",
                        "type": "boolean"
                      },
                      "order": {
                        "default": "pinnedFirst",
                        "description": "pinnedFirst (default), or changed: most recently changed first",
                        "type": "string",
                        "enum": ["pinnedFirst", "changed"]
                      },
                      "limit": { "default": 30, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": { "type": "string", "maxLength": 300 }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "tag": "shopping", "limit": 10 } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "notes": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "title": { "type": "string" },
                              "excerpt": {
                                "type": "string",
                                "description": "The start of the body, on one line"
                              },
                              "folderId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ]
                              },
                              "tags": { "type": "array", "items": { "type": "string" } },
                              "pinned": { "type": "boolean" },
                              "archived": { "type": "boolean" },
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": ["lavender", "sky", "apricot", "lime"],
                                    "description": "A colour that makes the note stand out on the board"
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" },
                              "attached": {
                                "type": "object",
                                "properties": {
                                  "count": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991,
                                    "description": "How many files are attached"
                                  },
                                  "pictures": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991,
                                    "description": "How many of them are pictures"
                                  },
                                  "cover": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "id": { "type": "string", "format": "uuid" },
                                          "url": {
                                            "type": "string",
                                            "format": "uri",
                                            "description": "A short-lived link to show it (5 minutes)"
                                          }
                                        },
                                        "required": ["id", "url"]
                                      },
                                      { "type": "null" }
                                    ],
                                    "description": "The picture shown first in the note (or the first one attached)"
                                  },
                                  "file": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "name": { "type": "string" },
                                          "contentType": { "type": "string" },
                                          "size": {
                                            "type": "integer",
                                            "minimum": -9007199254740991,
                                            "maximum": 9007199254740991
                                          }
                                        },
                                        "required": ["name", "contentType", "size"]
                                      },
                                      { "type": "null" }
                                    ],
                                    "description": "The first attached file that is not a picture"
                                  }
                                },
                                "required": ["count", "pictures", "cover", "file"],
                                "description": "The note’s attachments in short"
                              }
                            },
                            "required": [
                              "id",
                              "title",
                              "excerpt",
                              "folderId",
                              "tags",
                              "pinned",
                              "archived",
                              "color",
                              "revision",
                              "createdAt",
                              "updatedAt",
                              "attached"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many notes match, on every page"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["notes", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.search": {
      "post": {
        "operationId": "notes.search",
        "summary": "Search notes",
        "description": "Search notes by words in their title, body and attachments (text in PDFs and in pictures, read automatically). Typos in titles are forgiven. Supports \"exact phrases\", -excluded words and OR. Best matches first.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "query": { "type": "string", "minLength": 1, "maxLength": 200 },
                      "folderId": {
                        "description": "Only notes in this folder; null for notes at the top level",
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "description": "A folder id (from notes.folders)"
                          },
                          { "type": "null" }
                        ]
                      },
                      "tag": {
                        "description": "Only notes with this tag",
                        "type": "string",
                        "maxLength": 100
                      },
                      "includeArchived": { "default": true, "type": "boolean" },
                      "limit": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }
                    },
                    "required": ["query"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "query": "electricity bill" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "title": { "type": "string" },
                              "excerpt": {
                                "type": "string",
                                "description": "The start of the body, on one line"
                              },
                              "folderId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ]
                              },
                              "tags": { "type": "array", "items": { "type": "string" } },
                              "pinned": { "type": "boolean" },
                              "archived": { "type": "boolean" },
                              "color": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": ["lavender", "sky", "apricot", "lime"],
                                    "description": "A colour that makes the note stand out on the board"
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" },
                              "attached": {
                                "type": "object",
                                "properties": {
                                  "count": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991,
                                    "description": "How many files are attached"
                                  },
                                  "pictures": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991,
                                    "description": "How many of them are pictures"
                                  },
                                  "cover": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "id": { "type": "string", "format": "uuid" },
                                          "url": {
                                            "type": "string",
                                            "format": "uri",
                                            "description": "A short-lived link to show it (5 minutes)"
                                          }
                                        },
                                        "required": ["id", "url"]
                                      },
                                      { "type": "null" }
                                    ],
                                    "description": "The picture shown first in the note (or the first one attached)"
                                  },
                                  "file": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "name": { "type": "string" },
                                          "contentType": { "type": "string" },
                                          "size": {
                                            "type": "integer",
                                            "minimum": -9007199254740991,
                                            "maximum": 9007199254740991
                                          }
                                        },
                                        "required": ["name", "contentType", "size"]
                                      },
                                      { "type": "null" }
                                    ],
                                    "description": "The first attached file that is not a picture"
                                  }
                                },
                                "required": ["count", "pictures", "cover", "file"],
                                "description": "The note’s attachments in short"
                              },
                              "foundIn": {
                                "type": "array",
                                "items": { "type": "string" },
                                "description": "Attachments whose text matched (empty when the note itself matched)"
                              }
                            },
                            "required": [
                              "id",
                              "title",
                              "excerpt",
                              "folderId",
                              "tags",
                              "pinned",
                              "archived",
                              "color",
                              "revision",
                              "createdAt",
                              "updatedAt",
                              "attached",
                              "foundIn"
                            ]
                          }
                        }
                      },
                      "required": ["results"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.update": {
      "post": {
        "operationId": "notes.update",
        "summary": "Change a note",
        "description": "Change one or more fields of a note: title, whole body, folder (null for the top level), tags (replaces them), pinned, archived or colour (null for none). To add text or fix one passage, notes.append and notes.replaceText are safer than rewriting the body.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If the note changed since, the edit is refused so nothing is overwritten. Recommended for AI apps.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "title": { "type": "string", "minLength": 1, "maxLength": 200 },
                      "body": { "description": "The whole new body (Markdown)", "type": "string" },
                      "folderId": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "description": "A folder id (from notes.folders)"
                          },
                          { "type": "null" }
                        ]
                      },
                      "tags": {
                        "maxItems": 50,
                        "type": "array",
                        "items": { "type": "string", "maxLength": 100 },
                        "description": "Labels, e.g. [\"work\", \"home\"]. Stored lower-case."
                      },
                      "pinned": { "type": "boolean" },
                      "archived": {
                        "description": "Archived notes leave the normal list but stay searchable",
                        "type": "boolean"
                      },
                      "color": {
                        "anyOf": [
                          {
                            "type": "string",
                            "enum": ["lavender", "sky", "apricot", "lime"],
                            "description": "A colour that makes the note stand out on the board"
                          },
                          { "type": "null" }
                        ]
                      }
                    },
                    "required": ["noteId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "title": "Groceries for Saturday",
                  "revision": 3
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.append": {
      "post": {
        "operationId": "notes.append",
        "summary": "Add text to a note",
        "description": "Add text at the end of a note (on a new line). Safer than rewriting the whole body.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "text": {
                        "type": "string",
                        "minLength": 1,
                        "description": "Markdown to add"
                      },
                      "revision": {
                        "description": "The revision you last read. If the note changed since, the edit is refused so nothing is overwritten. Recommended for AI apps.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      }
                    },
                    "required": ["noteId", "text"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb", "text": "- oat milk" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.replaceText": {
      "post": {
        "operationId": "notes.replaceText",
        "summary": "Replace text in a note",
        "description": "Replace one exact passage of a note with new text (empty to remove it). The passage must appear exactly once: copy it from the note, with enough surrounding text to be unique.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "find": {
                        "type": "string",
                        "minLength": 1,
                        "description": "The exact text to replace"
                      },
                      "replace": { "type": "string", "description": "The new text" },
                      "revision": {
                        "description": "The revision you last read. If the note changed since, the edit is refused so nothing is overwritten. Recommended for AI apps.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      }
                    },
                    "required": ["noteId", "find", "replace"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "find": "- eggs",
                  "replace": "- 12 eggs"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.delete": {
      "post": {
        "operationId": "notes.delete",
        "summary": "Move a note to the trash",
        "description": "Move a note to the trash. It can be restored with notes.restore for 30 days, then it is deleted for good with its attachments.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If the note changed since, the edit is refused so nothing is overwritten. Recommended for AI apps.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      }
                    },
                    "required": ["noteId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" }
                      },
                      "required": ["id", "deletedAt", "restoreUntil"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.restore": {
      "post": {
        "operationId": "notes.restore",
        "summary": "Restore a note from the trash",
        "description": "Bring a note back from the trash, with its attachments.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      }
                    },
                    "required": ["noteId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "title": { "type": "string" },
                        "folderId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }]
                        },
                        "tags": { "type": "array", "items": { "type": "string" } },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "color": {
                          "anyOf": [
                            {
                              "type": "string",
                              "enum": ["lavender", "sky", "apricot", "lime"],
                              "description": "A colour that makes the note stand out on the board"
                            },
                            { "type": "null" }
                          ]
                        },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "createdAt": { "type": "string", "format": "date-time" },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "body": { "type": "string", "description": "Markdown" },
                        "attachments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                              },
                              "name": { "type": "string" },
                              "contentType": { "type": "string" },
                              "size": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "status": {
                                "type": "string",
                                "enum": ["pending", "ready"],
                                "description": "pending until the upload is finished"
                              },
                              "searchable": {
                                "type": "string",
                                "enum": ["pending", "done", "none"],
                                "description": "Whether its text has been read for search yet (none: no readable text)"
                              },
                              "url": {
                                "description": "A short-lived link to view or download it (5 minutes)",
                                "type": "string",
                                "format": "uri"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "contentType",
                              "size",
                              "status",
                              "searchable"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "title",
                        "folderId",
                        "tags",
                        "pinned",
                        "archived",
                        "color",
                        "revision",
                        "createdAt",
                        "updatedAt",
                        "body",
                        "attachments"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.trash": {
      "post": {
        "operationId": "notes.trash",
        "summary": "List notes in the trash",
        "description": "List notes in the trash (most recently deleted first), until when each can be restored, and how many are in it in all. Pass nextCursor back as cursor for the next page.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "limit": 20 } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "notes": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "title": { "type": "string" },
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" }
                            },
                            "required": ["id", "title", "deletedAt", "restoreUntil"]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many notes are in the trash in all"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["notes", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.deleteForever": {
      "post": {
        "operationId": "notes.deleteForever",
        "summary": "Delete notes in the trash for good",
        "description": "Delete notes that are in the trash for good, with their pictures and files: the ones named (noteIds), or the whole trash (all: true). It cannot be undone, so ask the person first. Notes not in the trash are refused: notes.delete moves a note there.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteIds": {
                        "description": "Notes in the trash to delete for good (from notes.trash)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The note id (from notes.list, notes.search or notes.create)"
                        }
                      },
                      "all": {
                        "description": "true: empty the whole trash instead",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "noteIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "notes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many notes were deleted for good"
                        },
                        "files": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many pictures and files went with them"
                        }
                      },
                      "required": ["notes", "files"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.attach": {
      "post": {
        "operationId": "notes.attach",
        "summary": "Attach a file to a note",
        "description": "Attach a picture or file (PDF, document, audio...) to a note. Chat apps send small files (up to 5 MB) inline as base64 in data. Otherwise give size and sha256 (the CLI fills them from --file <path>): the answer has an upload link to PUT the bytes to, then call notes.finishAttach. Show a picture in the body with ![caption](attachment:<id>) on a line of its own. To set how it shows, add a title: ![caption](attachment:<id> \"width=50 align=center crop=0.1,0.1,0.8,0.8\"): width is a percent of the text width (10 to 100; left out, the picture keeps its own size), align is left, center or right, and crop is the part kept as x,y,width,height fractions of the picture. Text in pictures and PDFs becomes searchable.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 255,
                        "description": "File name, e.g. receipt.jpg"
                      },
                      "contentType": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 200,
                        "description": "e.g. image/jpeg or application/pdf"
                      },
                      "data": {
                        "description": "The whole file as base64 (up to 5 MB): stored in one step",
                        "type": "string",
                        "maxLength": 6990508
                      },
                      "size": {
                        "description": "Bytes, when uploading with the link instead",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "sha256": {
                        "description": "Hex SHA-256 of the bytes, when uploading",
                        "type": "string"
                      }
                    },
                    "required": ["noteId", "name", "contentType"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "name": "receipt.jpg",
                  "contentType": "image/jpeg",
                  "data": "/9j/4AAQSkZJRg=="
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "attachment": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid",
                              "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                            },
                            "name": { "type": "string" },
                            "contentType": { "type": "string" },
                            "size": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "status": {
                              "type": "string",
                              "enum": ["pending", "ready"],
                              "description": "pending until the upload is finished"
                            },
                            "searchable": {
                              "type": "string",
                              "enum": ["pending", "done", "none"],
                              "description": "Whether its text has been read for search yet (none: no readable text)"
                            },
                            "url": {
                              "description": "A short-lived link to view or download it (5 minutes)",
                              "type": "string",
                              "format": "uri"
                            }
                          },
                          "required": ["id", "name", "contentType", "size", "status", "searchable"]
                        },
                        "upload": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "url": { "type": "string", "format": "uri" },
                                "method": { "type": "string", "const": "PUT" },
                                "headers": {
                                  "type": "object",
                                  "propertyNames": { "type": "string" },
                                  "description": "Send exactly these headers with the bytes"
                                },
                                "expiresAt": { "type": "string", "format": "date-time" }
                              },
                              "required": ["url", "method", "headers", "expiresAt"]
                            },
                            { "type": "null" }
                          ]
                        },
                        "finish": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "operation": { "type": "string" },
                                "input": { "type": "object", "propertyNames": { "type": "string" } }
                              },
                              "required": ["operation", "input"]
                            },
                            { "type": "null" }
                          ],
                          "description": "After uploading, call this operation with this input (the CLI does it for you)"
                        }
                      },
                      "required": ["attachment", "upload", "finish"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.finishAttach": {
      "post": {
        "operationId": "notes.finishAttach",
        "summary": "Finish attaching a file",
        "description": "Confirm an attachment after its bytes were uploaded with the link from notes.attach.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "attachmentId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The attachment id (from notes.get or notes.attach)"
                      }
                    },
                    "required": ["noteId", "attachmentId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "attachmentId": "01a1927a-1071-7a71-994f-4180839c9a39"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "attachment": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid",
                              "description": "Use it in the body as ![caption](attachment:<id>) to show a picture inline (see notes.attach for its size, side and crop)"
                            },
                            "name": { "type": "string" },
                            "contentType": { "type": "string" },
                            "size": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "status": {
                              "type": "string",
                              "enum": ["pending", "ready"],
                              "description": "pending until the upload is finished"
                            },
                            "searchable": {
                              "type": "string",
                              "enum": ["pending", "done", "none"],
                              "description": "Whether its text has been read for search yet (none: no readable text)"
                            },
                            "url": {
                              "description": "A short-lived link to view or download it (5 minutes)",
                              "type": "string",
                              "format": "uri"
                            }
                          },
                          "required": ["id", "name", "contentType", "size", "status", "searchable"]
                        }
                      },
                      "required": ["attachment"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.detach": {
      "post": {
        "operationId": "notes.detach",
        "summary": "Delete an attachment",
        "description": "Remove an attachment from a note and delete the file. This cannot be undone. Remove any ![...](attachment:<id>) from the body too.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "noteId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The note id (from notes.list, notes.search or notes.create)"
                      },
                      "attachmentId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The attachment id (from notes.get or notes.attach)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["noteId", "attachmentId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "noteId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "attachmentId": "01a1927a-1071-7a71-994f-4180839c9a39"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean" }
                      },
                      "required": ["id", "deleted"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.folders": {
      "post": {
        "operationId": "notes.folders",
        "summary": "List note folders",
        "description": "List all note folders (a tree: each has its parentId, null at the top level) with how many notes are directly in each.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "folders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "parentId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "null at the top level"
                              },
                              "notes": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Notes directly inside it (not counting archived or deleted)"
                              }
                            },
                            "required": ["id", "name", "parentId", "notes"]
                          }
                        }
                      },
                      "required": ["folders"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.createFolder": {
      "post": {
        "operationId": "notes.createFolder",
        "summary": "Create a folder",
        "description": "Create a folder for notes, at the top level or inside another folder (5 levels at most).",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "parentId": {
                        "description": "Put it inside this folder",
                        "type": "string",
                        "format": "uuid"
                      }
                    },
                    "required": ["name"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "name": "Garden" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "parentId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }],
                          "description": "null at the top level"
                        },
                        "notes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Notes directly inside it (not counting archived or deleted)"
                        }
                      },
                      "required": ["id", "name", "parentId", "notes"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.updateFolder": {
      "post": {
        "operationId": "notes.updateFolder",
        "summary": "Rename or move a folder",
        "description": "Rename a folder or move it into another folder (parentId null moves it to the top level). Its notes and subfolders move with it.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "folderId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A folder id (from notes.folders)"
                      },
                      "name": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "parentId": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "description": "A folder id (from notes.folders)"
                          },
                          { "type": "null" }
                        ]
                      }
                    },
                    "required": ["folderId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "folderId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "name": "Cooking" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "parentId": {
                          "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }],
                          "description": "null at the top level"
                        },
                        "notes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Notes directly inside it (not counting archived or deleted)"
                        }
                      },
                      "required": ["id", "name", "parentId", "notes"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.deleteFolder": {
      "post": {
        "operationId": "notes.deleteFolder",
        "summary": "Delete a folder",
        "description": "Delete a folder. It must be empty, unless moveContentsUp is true: then its notes and subfolders move to the folder above (or the top level). Notes are never deleted by this.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "folderId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A folder id (from notes.folders)"
                      },
                      "moveContentsUp": {
                        "default": false,
                        "description": "Move what is inside to the parent folder instead of refusing",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["folderId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "folderId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "movedNotes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "movedFolders": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["id", "movedNotes", "movedFolders"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.tags": {
      "post": {
        "operationId": "notes.tags",
        "summary": "List tags",
        "description": "List every tag used on notes (not counting the trash), most used first.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "tag": { "type": "string" },
                              "notes": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["tag", "notes"]
                          }
                        }
                      },
                      "required": ["tags"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.renameTag": {
      "post": {
        "operationId": "notes.renameTag",
        "summary": "Rename a tag everywhere",
        "description": "Rename a tag on every note that has it (merging into the new tag if a note already has both).",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "from": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "to": { "type": "string", "minLength": 1, "maxLength": 100 }
                    },
                    "required": ["from", "to"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "from": "job", "to": "work" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "notesChanged": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["notesChanged"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/notes.removeTag": {
      "post": {
        "operationId": "notes.removeTag",
        "summary": "Remove a tag everywhere",
        "description": "Remove a tag from every note that has it. The notes themselves stay.",
        "tags": ["notes"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "tag": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["tag"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "tag": "old" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "notesChanged": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["notesChanged"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.create": {
      "post": {
        "operationId": "lists.create",
        "summary": "Create a list",
        "description": "Create a list (a checklist or to-do list) with its own columns. Every item has a text, a tick and an optional due day; columns can be text, number, date, checkbox, choice, multi-choice, link or rating. copyOf makes a new list with the columns of another one, and its items unticked when withItems is true. Add items with lists.addItems.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "description": { "type": "string", "maxLength": 1000 },
                      "fields": {
                        "description": "The list’s own columns, in order",
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 50,
                              "description": "The column name, e.g. \"qty\" or \"aisle\""
                            },
                            "type": {
                              "type": "string",
                              "enum": [
                                "text",
                                "number",
                                "date",
                                "checkbox",
                                "choice",
                                "multi-choice",
                                "link",
                                "rating"
                              ]
                            },
                            "options": {
                              "description": "The choices, for choice and multi-choice columns",
                              "maxItems": 100,
                              "type": "array",
                              "items": { "type": "string", "minLength": 1, "maxLength": 100 }
                            }
                          },
                          "required": ["name", "type"]
                        }
                      },
                      "copyOf": {
                        "description": "Copy another list’s columns",
                        "type": "string",
                        "format": "uuid"
                      },
                      "withItems": {
                        "default": false,
                        "description": "With copyOf: also copy its items (all unticked)",
                        "type": "boolean"
                      },
                      "pinned": { "type": "boolean" }
                    },
                    "required": ["name"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "name": "Groceries",
                  "fields": [
                    { "name": "qty", "type": "number" },
                    { "name": "aisle", "type": "choice", "options": ["Produce", "Dairy", "Bakery"] }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.get": {
      "post": {
        "operationId": "lists.get",
        "summary": "Read a list’s columns",
        "description": "Read a list’s details: its columns (names, types and choices), default view and how many items are still to do. Read this before adding or changing items, to use the right column names. The items themselves come from lists.items.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.list": {
      "post": {
        "operationId": "lists.list",
        "summary": "List all lists",
        "description": "List your lists, pinned first, then most recently changed, with how many items each still has to do. Archived lists are not shown unless archived is true. unfinished keeps only lists with items still to tick. query keeps the lists whose name contains it, in any case and with or without accents (lists.search also forgives typos). Pass nextCursor back as cursor for the next page.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "archived": {
                        "default": false,
                        "description": "true lists the archive instead",
                        "type": "boolean"
                      },
                      "query": {
                        "description": "Only lists named like this",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100
                      },
                      "unfinished": {
                        "default": false,
                        "description": "true: only lists with items still to tick",
                        "type": "boolean"
                      },
                      "limit": { "default": 100, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "nextCursor from the previous page, for the page after it"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "lists": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "description": { "type": "string" },
                              "items": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Items in the list (not counting the trash)"
                              },
                              "unticked": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Items still to do"
                              },
                              "pinned": { "type": "boolean" },
                              "archived": { "type": "boolean" },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "name",
                              "description",
                              "items",
                              "unticked",
                              "pinned",
                              "archived",
                              "revision",
                              "updatedAt"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many lists match, on every page"
                        },
                        "totalItems": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items all the matching lists hold together"
                        },
                        "totalUnticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many of those are still to do"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["lists", "total", "totalItems", "totalUnticked", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.update": {
      "post": {
        "operationId": "lists.update",
        "summary": "Change a list",
        "description": "Change a list’s name, description, pinned or archived state, or its default view (sort and grouping, e.g. group by an aisle column to show sections). Columns change with lists.addField, lists.updateField and lists.removeField.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "name": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "description": { "type": "string", "maxLength": 1000 },
                      "pinned": { "type": "boolean" },
                      "archived": {
                        "description": "Archived lists leave the normal overview",
                        "type": "boolean"
                      },
                      "view": {
                        "type": "object",
                        "properties": {
                          "sort": {
                            "type": "object",
                            "properties": {
                              "by": { "type": "string", "minLength": 1, "maxLength": 50 },
                              "direction": {
                                "default": "asc",
                                "type": "string",
                                "enum": ["asc", "desc"]
                              }
                            },
                            "required": ["by"]
                          },
                          "group": {
                            "anyOf": [
                              { "type": "string", "minLength": 1, "maxLength": 50 },
                              { "type": "null" }
                            ]
                          }
                        },
                        "description": "How the list shows by default. sort.by: position (your order), text, ticked, due, created or a column; group: ticked, due, or a choice, checkbox, rating or date column (null stops grouping)."
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "name": "Weekly shop",
                  "revision": 2
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.addField": {
      "post": {
        "operationId": "lists.addField",
        "summary": "Add a column to a list",
        "description": "Add a column to a list (up to 30). Types: text, number, date, checkbox, choice and multi-choice (with options), link, rating (1 to 5). It is empty on existing items.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50,
                        "description": "The column name, e.g. \"qty\" or \"aisle\""
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "text",
                          "number",
                          "date",
                          "checkbox",
                          "choice",
                          "multi-choice",
                          "link",
                          "rating"
                        ]
                      },
                      "options": {
                        "description": "The choices, for choice and multi-choice columns",
                        "maxItems": 100,
                        "type": "array",
                        "items": { "type": "string", "minLength": 1, "maxLength": 100 }
                      },
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "before": {
                        "description": "Put it before this column (default: at the end)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50
                      }
                    },
                    "required": ["name", "type", "listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "name": "price",
                  "type": "number"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.updateField": {
      "post": {
        "operationId": "lists.updateField",
        "summary": "Change a column",
        "description": "Change a column: rename it (items keep their values), replace its options, move it before another column, or change its type when no value is lost (e.g. number to text, choice to multi-choice, multi-choice to choice when no item has more than one picked, text to choice, which turns its values into options). Removing an option that items use is refused.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "column": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50,
                        "description": "The column’s current name"
                      },
                      "name": {
                        "description": "A new name",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "text",
                          "number",
                          "date",
                          "checkbox",
                          "choice",
                          "multi-choice",
                          "link",
                          "rating"
                        ]
                      },
                      "options": {
                        "description": "The full new set of options",
                        "maxItems": 100,
                        "type": "array",
                        "items": { "type": "string", "minLength": 1, "maxLength": 100 }
                      },
                      "before": {
                        "description": "Move it before this column",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50
                      }
                    },
                    "required": ["listId", "column"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "column": "qty",
                  "name": "quantity"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.removeField": {
      "post": {
        "operationId": "lists.removeField",
        "summary": "Remove a column",
        "description": "Remove a column from a list and delete its values from every item, for good (it cannot be undone). Ask the person first.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "column": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50,
                        "description": "The column’s current name"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["listId", "column"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "column": "price" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.items": {
      "post": {
        "operationId": "lists.items",
        "summary": "Read a list’s items",
        "description": "Read a list’s items with their values by column name. By default in the list’s own order (or its saved view), ticked items last. Filter by the tick, by text, due day or any column (tests: is, isNot, contains, lessThan, atMost, greaterThan, atLeast, isEmpty, isNotEmpty); sort and group by a column. query finds items by words in their text or any text or link column (any case, with or without accents; every word must appear). For a long list, filter or search rather than reading every page.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "ticked": {
                        "description": "Only ticked (true) or only unticked (false) items",
                        "type": "boolean"
                      },
                      "filters": {
                        "default": [],
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "column": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 50,
                              "description": "A column name, or text or due"
                            },
                            "test": {
                              "type": "string",
                              "enum": [
                                "is",
                                "isNot",
                                "contains",
                                "lessThan",
                                "atMost",
                                "greaterThan",
                                "atLeast",
                                "isEmpty",
                                "isNotEmpty"
                              ]
                            },
                            "value": {
                              "description": "What to compare with (not for isEmpty / isNotEmpty)"
                            }
                          },
                          "required": ["column", "test"]
                        }
                      },
                      "query": {
                        "description": "Only items with these words in their text or a text or link column (any case, accents ignored)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "sort": {
                        "description": "position, text, ticked, due, created or a column (default: the list’s view)",
                        "type": "object",
                        "properties": {
                          "by": { "type": "string", "minLength": 1, "maxLength": 50 },
                          "direction": {
                            "default": "asc",
                            "type": "string",
                            "enum": ["asc", "desc"]
                          }
                        },
                        "required": ["by"]
                      },
                      "group": {
                        "description": "Group by ticked, due or a column",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 50
                      },
                      "itemIds": {
                        "description": "Only these items, e.g. to read one again",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An item id (from lists.items or lists.search)"
                        }
                      },
                      "limit": { "default": 100, "type": "integer", "minimum": 1, "maximum": 500 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "list": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "name": { "type": "string" }
                          },
                          "required": ["id", "name"]
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "groups": {
                          "description": "Each group’s value (as item values show it) and how many matching items it has, and how many of those are still to do, in order",
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "value": {},
                              "count": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "unticked": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["value", "count", "unticked"]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items matching the filters and the query"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["list", "items", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.addItems": {
      "post": {
        "operationId": "lists.addItems",
        "summary": "Add items to a list",
        "description": "Add one or more items (up to 100) to a list in one call, at the end or before another item. Each item has a text, an optional due day and values for the list’s columns by name (read the columns with lists.get first). Add several at once rather than one call each.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "items": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "text": { "type": "string", "minLength": 1, "maxLength": 500 },
                            "due": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "values": {
                              "type": "object",
                              "propertyNames": { "type": "string" },
                              "description": "Values by column name, e.g. {\"qty\": 2, \"aisle\": \"Dairy\"}; null clears one. Read the list first (lists.get) to see its columns."
                            }
                          },
                          "required": ["text"]
                        }
                      },
                      "before": {
                        "description": "Put them before this item (default: at the end)",
                        "type": "string",
                        "format": "uuid"
                      },
                      "addMissingOptions": {
                        "default": false,
                        "description": "Add choice options that do not exist yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["listId", "items"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "items": [
                    { "text": "Eggs" },
                    { "text": "Flour", "values": { "qty": 2, "aisle": "Bakery" } }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "listId": { "type": "string", "format": "uuid" },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in this list"
                        }
                      },
                      "required": ["items", "listId", "unticked"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.updateItems": {
      "post": {
        "operationId": "lists.updateItems",
        "summary": "Change items",
        "description": "Change up to 100 items of one list: text, due day (null removes it) and column values by name (only the values given change; null clears one). To tick items use lists.tick; to move them, lists.moveItems.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "items": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "itemId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "An item id (from lists.items or lists.search)"
                            },
                            "revision": {
                              "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 9007199254740991
                            },
                            "text": { "type": "string", "minLength": 1, "maxLength": 500 },
                            "due": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "format": "date",
                                  "description": "A day, as YYYY-MM-DD"
                                },
                                { "type": "null" }
                              ]
                            },
                            "values": {
                              "type": "object",
                              "propertyNames": { "type": "string" },
                              "description": "Values by column name, e.g. {\"qty\": 2, \"aisle\": \"Dairy\"}; null clears one. Read the list first (lists.get) to see its columns."
                            }
                          },
                          "required": ["itemId"]
                        }
                      },
                      "addMissingOptions": {
                        "default": false,
                        "description": "Add choice options that do not exist yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["items"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "items": [
                    {
                      "itemId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                      "text": "Oat milk",
                      "values": { "qty": 3 }
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "listId": { "type": "string", "format": "uuid" },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in this list"
                        }
                      },
                      "required": ["items", "listId", "unticked"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.tick": {
      "post": {
        "operationId": "lists.tick",
        "summary": "Tick or untick items",
        "description": "Tick items as done (or untick them with ticked: false), up to 100 of one list at a time. The answer says how many are still to do and whether the list is now complete. To untick a whole list for reuse, lists.reset is simpler.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "itemIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An item id (from lists.items or lists.search)"
                        }
                      },
                      "ticked": { "default": true, "type": "boolean" }
                    },
                    "required": ["itemIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "itemIds": ["01a19279-eb99-775d-bebf-12c59f611dfb"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "listId": { "type": "string", "format": "uuid" },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in this list"
                        },
                        "completed": {
                          "type": "boolean",
                          "description": "True when this call ticked the list’s last item"
                        }
                      },
                      "required": ["items", "listId", "unticked", "completed"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.tickMatching": {
      "post": {
        "operationId": "lists.tickMatching",
        "summary": "Tick every matching item",
        "description": "Tick (or untick, with to: unticked) every item of a list that matches the filters and query, however many: e.g. every item in the Dairy aisle. For a few known items, lists.tick is simpler.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "ticked": {
                        "description": "Only ticked (true) or only unticked (false) items",
                        "type": "boolean"
                      },
                      "filters": {
                        "default": [],
                        "description": "The same filters as lists.items; none: every item",
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "column": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 50,
                              "description": "A column name, or text or due"
                            },
                            "test": {
                              "type": "string",
                              "enum": [
                                "is",
                                "isNot",
                                "contains",
                                "lessThan",
                                "atMost",
                                "greaterThan",
                                "atLeast",
                                "isEmpty",
                                "isNotEmpty"
                              ]
                            },
                            "value": {
                              "description": "What to compare with (not for isEmpty / isNotEmpty)"
                            }
                          },
                          "required": ["column", "test"]
                        }
                      },
                      "query": {
                        "description": "The same words as lists.items query: only items holding every word",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "to": {
                        "default": "ticked",
                        "type": "string",
                        "enum": ["ticked", "unticked"]
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "filters": [] }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        },
                        "completed": {
                          "type": "boolean",
                          "description": "True when this call ticked the list’s last item"
                        }
                      },
                      "required": ["listId", "count", "unticked", "completed"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.moveItems": {
      "post": {
        "operationId": "lists.moveItems",
        "summary": "Move items",
        "description": "Move items within their list (before another item, or to the end) or to another list. Moving to another list keeps the values of columns it has with the same name and type; others are dropped, and the answer says which.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "itemIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An item id (from lists.items or lists.search)"
                        }
                      },
                      "toListId": {
                        "description": "Another list (default: the same one)",
                        "type": "string",
                        "format": "uuid"
                      },
                      "before": {
                        "description": "Put them before this item (default: at the end)",
                        "type": "string",
                        "format": "uuid"
                      }
                    },
                    "required": ["itemIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "itemIds": ["01a19279-eb99-775d-bebf-12c59f611dfb"],
                  "before": "01a19279-ec12-7a31-8f02-3a1b2c3d4e5f"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "listId": { "type": "string", "format": "uuid" },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in this list"
                        },
                        "droppedColumns": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Columns the target list has no match for"
                        }
                      },
                      "required": ["items", "listId", "unticked", "droppedColumns"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.moveMatching": {
      "post": {
        "operationId": "lists.moveMatching",
        "summary": "Move every matching item to another list",
        "description": "Move every item of a list that matches the filters and query to the end of another list, however many. Values of columns the other list has with the same name and type are kept; others are dropped, and the answer says which. For a few known items, lists.moveItems is simpler.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "ticked": {
                        "description": "Only ticked (true) or only unticked (false) items",
                        "type": "boolean"
                      },
                      "filters": {
                        "default": [],
                        "description": "The same filters as lists.items; none: every item",
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "column": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 50,
                              "description": "A column name, or text or due"
                            },
                            "test": {
                              "type": "string",
                              "enum": [
                                "is",
                                "isNot",
                                "contains",
                                "lessThan",
                                "atMost",
                                "greaterThan",
                                "atLeast",
                                "isEmpty",
                                "isNotEmpty"
                              ]
                            },
                            "value": {
                              "description": "What to compare with (not for isEmpty / isNotEmpty)"
                            }
                          },
                          "required": ["column", "test"]
                        }
                      },
                      "query": {
                        "description": "The same words as lists.items query: only items holding every word",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "toListId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list to move them to"
                      }
                    },
                    "required": ["listId", "toListId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "ticked": false,
                  "filters": [],
                  "toListId": "01a19279-ec12-7a31-8f02-3a1b2c3d4e5f"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        },
                        "droppedColumns": {
                          "type": "array",
                          "items": { "type": "string" },
                          "description": "Columns the target list has no match for"
                        }
                      },
                      "required": ["listId", "count", "unticked", "droppedColumns"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.reset": {
      "post": {
        "operationId": "lists.reset",
        "summary": "Untick a whole list",
        "description": "Untick every item of a list, to use it again (a weekly shop, a packing list). Items and values stay as they are.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        }
                      },
                      "required": ["listId", "count", "unticked"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.due": {
      "post": {
        "operationId": "lists.due",
        "summary": "Items due across lists",
        "description": "Unticked items with a due day, across every list, soonest first: e.g. what is due this week (until the last day) or overdue (until yesterday). Archived lists are included.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "until": {
                        "type": "string",
                        "format": "date",
                        "description": "The last day to include, YYYY-MM-DD"
                      },
                      "from": {
                        "description": "The first day (default: no limit, so overdue items too)",
                        "type": "string",
                        "format": "date"
                      },
                      "limit": { "default": 100, "type": "integer", "minimum": 1, "maximum": 200 }
                    },
                    "required": ["until"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "until": "2026-11-07" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" },
                              "listName": { "type": "string" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt",
                              "listName"
                            ]
                          }
                        }
                      },
                      "required": ["items"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.search": {
      "post": {
        "operationId": "lists.search",
        "summary": "Search lists and items",
        "description": "Find items by their text and text values across every list (or one), and lists by name, best matches first. Typos are forgiven. Use it to find an item or a list the person names without knowing ids.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "query": { "type": "string", "minLength": 1, "maxLength": 200 },
                      "listId": {
                        "description": "Only items of this list",
                        "type": "string",
                        "format": "uuid"
                      },
                      "includeTicked": { "default": true, "type": "boolean" },
                      "limit": { "default": 20, "type": "integer", "minimum": 1, "maximum": 50 }
                    },
                    "required": ["query"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "query": "batteries" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "lists": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "unticked": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "archived": { "type": "boolean" }
                            },
                            "required": ["id", "name", "unticked", "archived"]
                          }
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "listId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "ticked": { "type": "boolean" },
                              "due": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "values": {
                                "type": "object",
                                "propertyNames": { "type": "string" },
                                "description": "Values by column name"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" },
                              "listName": { "type": "string" }
                            },
                            "required": [
                              "id",
                              "listId",
                              "text",
                              "ticked",
                              "due",
                              "values",
                              "revision",
                              "createdAt",
                              "updatedAt",
                              "listName"
                            ]
                          }
                        }
                      },
                      "required": ["lists", "items"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.delete": {
      "post": {
        "operationId": "lists.delete",
        "summary": "Move a list to the trash",
        "description": "Move a list, with its items, to the trash. It can be restored with lists.restore for 30 days, then it is deleted for good.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" },
                        "id": { "type": "string", "format": "uuid" }
                      },
                      "required": ["deletedAt", "restoreUntil", "id"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.restore": {
      "post": {
        "operationId": "lists.restore",
        "summary": "Restore a list from the trash",
        "description": "Bring a list back from the trash, with its items.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "description": { "type": "string" },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items in the list (not counting the trash)"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do"
                        },
                        "pinned": { "type": "boolean" },
                        "archived": { "type": "boolean" },
                        "revision": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "updatedAt": { "type": "string", "format": "date-time" },
                        "fields": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "number",
                                  "date",
                                  "checkbox",
                                  "choice",
                                  "multi-choice",
                                  "link",
                                  "rating"
                                ]
                              },
                              "options": { "type": "array", "items": { "type": "string" } },
                              "filled": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items (the trash too) hold a value in it"
                              },
                              "several": {
                                "description": "For several-choice columns: how many items have more than one choice picked",
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": ["name", "type", "filled"]
                          },
                          "description": "The list’s own columns, in order"
                        },
                        "view": {
                          "type": "object",
                          "properties": {
                            "sort": {
                              "description": "A column name, or text, ticked, due, position or created",
                              "type": "object",
                              "properties": {
                                "by": { "type": "string" },
                                "direction": { "type": "string", "enum": ["asc", "desc"] }
                              },
                              "required": ["by", "direction"]
                            },
                            "group": {
                              "description": "A column name, or ticked or due",
                              "type": "string"
                            }
                          },
                          "description": "How the list shows by default"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "description",
                        "items",
                        "unticked",
                        "pinned",
                        "archived",
                        "revision",
                        "updatedAt",
                        "fields",
                        "view"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.trash": {
      "post": {
        "operationId": "lists.trash",
        "summary": "List the trash",
        "description": "What is in the trash and until when it can be restored: deleted lists, or the deleted items of one list when listId is given (most recent first). Pass nextCursor back as cursor for the next page.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "description": "Show this list’s deleted items instead",
                        "type": "string",
                        "format": "uuid"
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "type": "string",
                        "maxLength": 300,
                        "description": "nextCursor from the previous page, for the page after it"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "lists": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" },
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "items": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many items it holds"
                              }
                            },
                            "required": ["deletedAt", "restoreUntil", "id", "name", "items"]
                          }
                        },
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" },
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" }
                            },
                            "required": ["deletedAt", "restoreUntil", "id", "text"]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many lists (or items) the whole trash holds"
                        },
                        "totalItems": {
                          "description": "For the lists: how many items all of them hold together",
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["lists", "items", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.deleteItems": {
      "post": {
        "operationId": "lists.deleteItems",
        "summary": "Move items to the trash",
        "description": "Move items of one list to the trash (up to 100). They can be restored with lists.restoreItems for 30 days. To remove every ticked item, lists.clearTicked is simpler.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "itemIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An item id (from lists.items or lists.search)"
                        }
                      }
                    },
                    "required": ["itemIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "itemIds": ["01a19279-eb99-775d-bebf-12c59f611dfb"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        },
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" }
                      },
                      "required": ["listId", "count", "unticked", "deletedAt", "restoreUntil"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.deleteMatching": {
      "post": {
        "operationId": "lists.deleteMatching",
        "summary": "Move every matching item to the trash",
        "description": "Move every item of a list that matches the filters and query to the trash, however many (restorable for 30 days with lists.restoreItems). For a few known items, lists.deleteItems is simpler; for the ticked ones, lists.clearTicked.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      },
                      "ticked": {
                        "description": "Only ticked (true) or only unticked (false) items",
                        "type": "boolean"
                      },
                      "filters": {
                        "default": [],
                        "description": "The same filters as lists.items; none: every item",
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "column": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 50,
                              "description": "A column name, or text or due"
                            },
                            "test": {
                              "type": "string",
                              "enum": [
                                "is",
                                "isNot",
                                "contains",
                                "lessThan",
                                "atMost",
                                "greaterThan",
                                "atLeast",
                                "isEmpty",
                                "isNotEmpty"
                              ]
                            },
                            "value": {
                              "description": "What to compare with (not for isEmpty / isNotEmpty)"
                            }
                          },
                          "required": ["column", "test"]
                        }
                      },
                      "query": {
                        "description": "The same words as lists.items query: only items holding every word",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "filters": [{ "column": "due", "test": "lessThan", "value": "2026-11-01" }]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        },
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" }
                      },
                      "required": ["listId", "count", "unticked", "deletedAt", "restoreUntil"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.restoreItems": {
      "post": {
        "operationId": "lists.restoreItems",
        "summary": "Restore items from the trash",
        "description": "Bring items back from the trash, at the end of their list. Name them (itemIds, found with lists.trash and a listId), or give the listId and deletedAt of a lists.deleteItems or lists.deleteMatching answer to bring back all it moved.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "itemIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An item id (from lists.items or lists.search)"
                        }
                      },
                      "listId": {
                        "description": "With deletedAt: the list the items were deleted from",
                        "type": "string",
                        "format": "uuid"
                      },
                      "deletedAt": {
                        "description": "The deletedAt of a delete answer: brings back all it moved",
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "itemIds": ["01a19279-eb99-775d-bebf-12c59f611dfb"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        }
                      },
                      "required": ["listId", "count", "unticked"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.clearTicked": {
      "post": {
        "operationId": "lists.clearTicked",
        "summary": "Clear ticked items",
        "description": "Move every ticked item of a list to the trash (restorable for 30 days with lists.restoreItems). To keep the items and only untick them, use lists.reset.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The list id (from lists.list, lists.search or lists.create)"
                      }
                    },
                    "required": ["listId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "listId": { "type": "string", "format": "uuid" },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items this changed"
                        },
                        "unticked": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Items still to do in the list"
                        }
                      },
                      "required": ["listId", "count", "unticked"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/lists.deleteForever": {
      "post": {
        "operationId": "lists.deleteForever",
        "summary": "Delete lists in the trash for good",
        "description": "Delete lists that are in the trash for good, with their items: the ones named (listIds), or the whole trash (all: true). It cannot be undone, so ask the person first. Lists not in the trash are refused: lists.delete moves a list there.",
        "tags": ["lists"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "listIds": {
                        "description": "Lists in the trash to delete for good (from lists.trash)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The list id (from lists.list, lists.search or lists.create)"
                        }
                      },
                      "all": {
                        "description": "true: empty the whole trash instead",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "listIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "lists": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many lists were deleted for good"
                        },
                        "items": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many items went with them"
                        }
                      },
                      "required": ["lists", "items"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.add": {
      "post": {
        "operationId": "expenses.add",
        "summary": "Log spending or income",
        "description": "Log up to 100 amounts spent or received in one call (log several at once rather than one call each). Each has an amount, a currency (default: the home currency), a day (default: today), a category by name (default: Other), an optional merchant and note, and a receipt (receiptId) to put on it. Amounts in another currency are converted with that day’s stored rate, or the bank’s rate when given. If the person has no home currency yet, the first currency given becomes it; say so.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entries": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "amount": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000000,
                              "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                            },
                            "currency": {
                              "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "kind": {
                              "default": "spending",
                              "type": "string",
                              "enum": ["spending", "income"],
                              "description": "spending (money out, the default) or income (money in)"
                            },
                            "category": {
                              "description": "A category name (expenses.categories)",
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 60
                            },
                            "merchant": { "default": "", "type": "string", "maxLength": 120 },
                            "note": { "default": "", "type": "string", "maxLength": 500 },
                            "rate": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000,
                              "description": "The rate the bank used: units of the home currency per one unit of this currency. Without it, the stored rate of that day is used."
                            },
                            "receiptId": {
                              "description": "A receipt (expenses.attachReceipt) to put on it",
                              "type": "string",
                              "format": "uuid"
                            }
                          },
                          "required": ["amount"]
                        }
                      },
                      "addMissingCategories": {
                        "default": false,
                        "description": "Make categories that do not exist yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["entries"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "entries": [
                    { "amount": 45, "category": "Food", "merchant": "Café Clock", "note": "Lunch" }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "day": { "type": "string", "format": "date" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency; null while the rate of its day is not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"],
                                "description": "same (no conversion), daily (that day’s rate), person (typed), pending"
                              },
                              "checkAmount": {
                                "type": "boolean",
                                "description": "Written by a recurring bill whose amount changes: check it"
                              },
                              "recurringId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The recurring bill or income that wrote it (expenses.recurring), if any"
                              },
                              "receiptIds": {
                                "type": "array",
                                "items": { "type": "string", "format": "uuid" },
                                "description": "Receipts attached to it (expenses.readReceipt reads one)"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "day",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateDay",
                              "rateSource",
                              "checkAmount",
                              "recurringId",
                              "receiptIds",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "homeCurrency": { "type": "string" },
                        "homeCurrencySet": {
                          "type": "boolean",
                          "description": "True when this call set the home currency (tell the person)"
                        }
                      },
                      "required": ["entries", "homeCurrency", "homeCurrencySet"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.update": {
      "post": {
        "operationId": "expenses.update",
        "summary": "Change entries",
        "description": "Change up to 100 entries: amount, currency, day, kind, category, merchant, note, the bank’s rate (null goes back to the day’s stored rate), or add a receipt (receiptId). Only what is given changes.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entries": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "entryId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "An entry id (from expenses.entries or expenses.add)"
                            },
                            "revision": {
                              "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 9007199254740991
                            },
                            "amount": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000000,
                              "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                            },
                            "currency": {
                              "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "kind": {
                              "type": "string",
                              "enum": ["spending", "income"],
                              "description": "spending (money out, the default) or income (money in)"
                            },
                            "category": { "type": "string", "minLength": 1, "maxLength": 60 },
                            "merchant": { "type": "string", "maxLength": 120 },
                            "note": { "type": "string", "maxLength": 500 },
                            "rate": {
                              "anyOf": [
                                {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 1000000000,
                                  "description": "The rate the bank used: units of the home currency per one unit of this currency. Without it, the stored rate of that day is used."
                                },
                                { "type": "null" }
                              ]
                            },
                            "receiptId": {
                              "description": "A receipt (expenses.attachReceipt) to add to it",
                              "type": "string",
                              "format": "uuid"
                            }
                          },
                          "required": ["entryId"]
                        }
                      },
                      "addMissingCategories": {
                        "default": false,
                        "description": "Make categories that do not exist yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["entries"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "entries": [{ "entryId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "amount": 35 }]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "day": { "type": "string", "format": "date" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency; null while the rate of its day is not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"],
                                "description": "same (no conversion), daily (that day’s rate), person (typed), pending"
                              },
                              "checkAmount": {
                                "type": "boolean",
                                "description": "Written by a recurring bill whose amount changes: check it"
                              },
                              "recurringId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The recurring bill or income that wrote it (expenses.recurring), if any"
                              },
                              "receiptIds": {
                                "type": "array",
                                "items": { "type": "string", "format": "uuid" },
                                "description": "Receipts attached to it (expenses.readReceipt reads one)"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "day",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateDay",
                              "rateSource",
                              "checkAmount",
                              "recurringId",
                              "receiptIds",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        }
                      },
                      "required": ["entries"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.moveToCategory": {
      "post": {
        "operationId": "expenses.moveToCategory",
        "summary": "Move matching entries to a category",
        "description": "Move every entry that matches the filters of expenses.entries (matching) to one category, however many there are. The matching entries must all be spending or all income: add kind to matching when unsure. For a few entries named by id, expenses.update works too.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "matching": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "description": "First day, included",
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "description": "Last day, included",
                            "type": "string",
                            "format": "date"
                          },
                          "kind": {
                            "description": "Only spending or only income (default: both)",
                            "type": "string",
                            "enum": ["spending", "income"]
                          },
                          "category": {
                            "description": "Only this category (a name)",
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60
                          },
                          "categories": {
                            "description": "Only entries in any of these categories (names)",
                            "minItems": 1,
                            "maxItems": 100,
                            "type": "array",
                            "items": { "type": "string", "minLength": 1, "maxLength": 60 }
                          },
                          "hasReceipt": {
                            "description": "true: only entries with a receipt; false: only entries without one",
                            "type": "boolean"
                          },
                          "currency": {
                            "description": "Only entries in this currency",
                            "type": "string"
                          },
                          "query": {
                            "description": "Words in the merchant or note",
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200
                          },
                          "checkAmount": {
                            "description": "Only entries marked to check (true)",
                            "type": "boolean"
                          }
                        },
                        "description": "The filters of expenses.entries"
                      },
                      "category": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60,
                        "description": "The category to move them to (a name)"
                      },
                      "addMissingCategories": {
                        "default": false,
                        "description": "Make the category when it does not exist yet instead of refusing",
                        "type": "boolean"
                      }
                    },
                    "required": ["matching", "category"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "matching": { "query": "uber", "kind": "spending" },
                  "category": "Transport"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "moved": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many entries moved"
                        },
                        "category": {
                          "description": "The category they are in now (null: none moved)",
                          "type": ["string", "null"]
                        }
                      },
                      "required": ["moved", "category"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.entries": {
      "post": {
        "operationId": "expenses.entries",
        "summary": "List or search entries",
        "description": "Entries spent or received, newest day first (or by amount, category or merchant), filtered by days, kind, categories, receipt, currency or words in the merchant and note. total is how many match across every page. For sums use expenses.totals instead of adding up pages.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "description": "First day, included",
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "description": "Last day, included",
                        "type": "string",
                        "format": "date"
                      },
                      "kind": {
                        "description": "Only spending or only income (default: both)",
                        "type": "string",
                        "enum": ["spending", "income"]
                      },
                      "category": {
                        "description": "Only this category (a name)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "categories": {
                        "description": "Only entries in any of these categories (names)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": { "type": "string", "minLength": 1, "maxLength": 60 }
                      },
                      "hasReceipt": {
                        "description": "true: only entries with a receipt; false: only entries without one",
                        "type": "boolean"
                      },
                      "currency": {
                        "description": "Only entries in this currency",
                        "type": "string"
                      },
                      "query": {
                        "description": "Words in the merchant or note",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "checkAmount": {
                        "description": "Only entries marked to check (true)",
                        "type": "boolean"
                      },
                      "sort": {
                        "default": "day",
                        "description": "day, amount (in the home currency), category (its name) or where (merchant)",
                        "type": "string",
                        "enum": ["day", "amount", "category", "where"]
                      },
                      "direction": {
                        "description": "Default: newest and largest first, names from A",
                        "type": "string",
                        "enum": ["asc", "desc"]
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "from": "2026-10-01", "to": "2026-10-31", "category": "Food" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "day": { "type": "string", "format": "date" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency; null while the rate of its day is not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"],
                                "description": "same (no conversion), daily (that day’s rate), person (typed), pending"
                              },
                              "checkAmount": {
                                "type": "boolean",
                                "description": "Written by a recurring bill whose amount changes: check it"
                              },
                              "recurringId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The recurring bill or income that wrote it (expenses.recurring), if any"
                              },
                              "receiptIds": {
                                "type": "array",
                                "items": { "type": "string", "format": "uuid" },
                                "description": "Receipts attached to it (expenses.readReceipt reads one)"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "day",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateDay",
                              "rateSource",
                              "checkAmount",
                              "recurringId",
                              "receiptIds",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Entries matching the filters, across every page"
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "homeCurrency": { "type": ["string", "null"] },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Entries whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": [
                        "entries",
                        "total",
                        "nextCursor",
                        "homeCurrency",
                        "waitingForRates"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.totals": {
      "post": {
        "operationId": "expenses.totals",
        "summary": "Add up spending and income",
        "description": "Totals of spending and income in the home currency, for any days, grouped by category, month or day (or one total), with the same filters as expenses.entries. One call answers “how much did I spend on food in October”; never add up pages of entries instead. With limit, only the largest groups (e.g. the top 3 categories), and groupCount says how many there are.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "description": "First day, included",
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "description": "Last day, included",
                        "type": "string",
                        "format": "date"
                      },
                      "kind": {
                        "description": "Only spending or only income (default: both)",
                        "type": "string",
                        "enum": ["spending", "income"]
                      },
                      "category": {
                        "description": "Only this category (a name)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "categories": {
                        "description": "Only entries in any of these categories (names)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": { "type": "string", "minLength": 1, "maxLength": 60 }
                      },
                      "hasReceipt": {
                        "description": "true: only entries with a receipt; false: only entries without one",
                        "type": "boolean"
                      },
                      "currency": {
                        "description": "Only entries in this currency",
                        "type": "string"
                      },
                      "query": {
                        "description": "Words in the merchant or note",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "checkAmount": {
                        "description": "Only entries marked to check (true)",
                        "type": "boolean"
                      },
                      "groupBy": {
                        "default": "category",
                        "type": "string",
                        "enum": ["category", "month", "day", "none"]
                      },
                      "limit": {
                        "description": "Only this many groups, the largest spending first (then income); groupCount says how many there are. Without it: every group, in key order",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 100
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "from": "2026-10-01", "to": "2026-10-31", "groupBy": "category" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "spending": { "type": "number" },
                        "income": { "type": "number" },
                        "net": { "type": "number", "description": "income minus spending" },
                        "entries": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many entries match, ones waiting for a rate included"
                        },
                        "currency": {
                          "description": "The home currency the totals are in",
                          "type": ["string", "null"]
                        },
                        "groups": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "spending": { "type": "number" },
                              "income": { "type": "number" },
                              "net": { "type": "number", "description": "income minus spending" },
                              "entries": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many entries match, ones waiting for a rate included"
                              },
                              "key": {
                                "type": "string",
                                "description": "The category name, month (YYYY-MM), day, or all"
                              }
                            },
                            "required": ["spending", "income", "net", "entries", "key"]
                          }
                        },
                        "groupCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many groups there are, shown or not"
                        },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Entries whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": [
                        "spending",
                        "income",
                        "net",
                        "entries",
                        "currency",
                        "groups",
                        "groupCount",
                        "waitingForRates"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.categories": {
      "post": {
        "operationId": "expenses.categories",
        "summary": "List categories",
        "description": "The categories entries can have, spending ones and income ones. A space starts with Food, Transport, Home, Bills, Health, Fun, Shopping and Other, plus Salary and Other income.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": { "includeArchived": { "default": false, "type": "boolean" } }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "categories": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "archived": { "type": "boolean" },
                              "entries": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many entries it has, not counting the trash"
                              }
                            },
                            "required": ["id", "name", "kind", "archived", "entries"]
                          }
                        }
                      },
                      "required": ["categories"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.addCategory": {
      "post": {
        "operationId": "expenses.addCategory",
        "summary": "Add a category",
        "description": "Add a spending (default) or income category.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": { "type": "string", "minLength": 1, "maxLength": 60 },
                      "kind": {
                        "default": "spending",
                        "type": "string",
                        "enum": ["spending", "income"],
                        "description": "spending (money out, the default) or income (money in)"
                      }
                    },
                    "required": ["name"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "name": "Pets" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "kind": { "type": "string", "enum": ["spending", "income"] },
                        "archived": { "type": "boolean" }
                      },
                      "required": ["id", "name", "kind", "archived"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.updateCategory": {
      "post": {
        "operationId": "expenses.updateCategory",
        "summary": "Rename or archive a category",
        "description": "Rename a category (its entries follow) or archive it: an archived category is no longer offered, but its entries keep it. archived: false brings it back.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "categoryId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A category id (from expenses.categories)"
                      },
                      "name": { "type": "string", "minLength": 1, "maxLength": 60 },
                      "archived": { "type": "boolean" }
                    },
                    "required": ["categoryId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "categoryId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "name": "Groceries"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "kind": { "type": "string", "enum": ["spending", "income"] },
                        "archived": { "type": "boolean" }
                      },
                      "required": ["id", "name", "kind", "archived"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.budgets": {
      "post": {
        "operationId": "expenses.budgets",
        "summary": "See budgets",
        "description": "Each monthly budget with what was spent that month (default: this month), what is left and the share used, in the home currency. The budget for all spending comes first, then the most used (over budget first), then by category; limit keeps the first few, and total says how many there are.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "month": { "type": "string", "description": "A month, as YYYY-MM" },
                      "limit": {
                        "default": 50,
                        "description": "How many budgets to answer, the most relevant first",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 50
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "budgets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "category": {
                                "description": "The category it watches; null means all spending",
                                "type": ["string", "null"]
                              },
                              "budget": {
                                "type": "number",
                                "description": "The monthly amount, in its own currency"
                              },
                              "currency": { "type": "string" },
                              "amount": {
                                "description": "The monthly amount in the home currency",
                                "type": ["number", "null"]
                              },
                              "spent": {
                                "type": "number",
                                "description": "Spent this month, in the home currency"
                              },
                              "left": { "type": ["number", "null"] },
                              "share": {
                                "description": "Spent divided by the amount: 1 means all of it",
                                "type": ["number", "null"]
                              },
                              "alertAt": {
                                "anyOf": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  { "type": "null" }
                                ],
                                "description": "The heads-up share in percent (budgetReached fires there), or null for none"
                              }
                            },
                            "required": [
                              "id",
                              "category",
                              "budget",
                              "currency",
                              "amount",
                              "spent",
                              "left",
                              "share",
                              "alertAt"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many budgets there are in all"
                        }
                      },
                      "required": ["budgets", "total"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.setBudget": {
      "post": {
        "operationId": "expenses.setBudget",
        "summary": "Set a monthly budget",
        "description": "Set the monthly budget for a spending category, or for all spending when no category is given, in the home currency. Setting it again changes the amount. alertAt is the heads-up share in percent (1 to 100, 80 by default, null for none): the person gets a heads-up in their inbox there and again at 100% (built in, nothing else to set up), and expenses.budgetReached fires at the same moments for automations.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "category": {
                        "description": "A spending category name; none means all",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "amount": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1000000000000,
                        "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                      },
                      "alertAt": {
                        "description": "Heads-up share in percent; null for none. Left as it was when not given (80 for a new budget)",
                        "anyOf": [
                          { "type": "integer", "minimum": 1, "maximum": 100 },
                          { "type": "null" }
                        ]
                      }
                    },
                    "required": ["amount"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "category": "Food", "amount": 2000 } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "category": {
                          "description": "The category it watches; null means all spending",
                          "type": ["string", "null"]
                        },
                        "budget": {
                          "type": "number",
                          "description": "The monthly amount, in its own currency"
                        },
                        "currency": { "type": "string" },
                        "amount": {
                          "description": "The monthly amount in the home currency",
                          "type": ["number", "null"]
                        },
                        "spent": {
                          "type": "number",
                          "description": "Spent this month, in the home currency"
                        },
                        "left": { "type": ["number", "null"] },
                        "share": {
                          "description": "Spent divided by the amount: 1 means all of it",
                          "type": ["number", "null"]
                        },
                        "alertAt": {
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            { "type": "null" }
                          ],
                          "description": "The heads-up share in percent (budgetReached fires there), or null for none"
                        }
                      },
                      "required": [
                        "id",
                        "category",
                        "budget",
                        "currency",
                        "amount",
                        "spent",
                        "left",
                        "share",
                        "alertAt"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.removeBudget": {
      "post": {
        "operationId": "expenses.removeBudget",
        "summary": "Remove a budget",
        "description": "Remove a monthly budget for good (entries are not touched). Ask the person first.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "budgetId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A budget id (from expenses.budgets)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["budgetId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "budgetId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": { "removed": { "type": "string", "format": "uuid" } },
                      "required": ["removed"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.delete": {
      "post": {
        "operationId": "expenses.delete",
        "summary": "Move entries to the trash",
        "description": "Move entries to the trash: the ones named (entryIds), or every entry that matches the filters of expenses.entries (matching), however many. They no longer count in totals or budgets, and can be restored with expenses.restore for 30 days (everything one call moved at once, with its deletedAt), then they are deleted for good.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entryIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An entry id (from expenses.entries or expenses.add)"
                        }
                      },
                      "matching": {
                        "description": "Every live entry that matches these filters (as in expenses.entries)",
                        "type": "object",
                        "properties": {
                          "from": {
                            "description": "First day, included",
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "description": "Last day, included",
                            "type": "string",
                            "format": "date"
                          },
                          "kind": {
                            "description": "Only spending or only income (default: both)",
                            "type": "string",
                            "enum": ["spending", "income"]
                          },
                          "category": {
                            "description": "Only this category (a name)",
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60
                          },
                          "categories": {
                            "description": "Only entries in any of these categories (names)",
                            "minItems": 1,
                            "maxItems": 100,
                            "type": "array",
                            "items": { "type": "string", "minLength": 1, "maxLength": 60 }
                          },
                          "hasReceipt": {
                            "description": "true: only entries with a receipt; false: only entries without one",
                            "type": "boolean"
                          },
                          "currency": {
                            "description": "Only entries in this currency",
                            "type": "string"
                          },
                          "query": {
                            "description": "Words in the merchant or note",
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200
                          },
                          "checkAmount": {
                            "description": "Only entries marked to check (true)",
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "entryIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "deleted": {
                          "type": "array",
                          "items": { "type": "string", "format": "uuid" },
                          "description": "The entries named (empty for matching)"
                        },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many entries went to the trash"
                        },
                        "deletedAt": {
                          "type": "string",
                          "format": "date-time",
                          "description": "expenses.restore with it brings all of them back"
                        },
                        "restoreUntil": { "type": "string", "format": "date-time" }
                      },
                      "required": ["deleted", "count", "deletedAt", "restoreUntil"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.restore": {
      "post": {
        "operationId": "expenses.restore",
        "summary": "Restore entries from the trash",
        "description": "Bring entries back from the trash: the ones named (entryIds), or everything one expenses.delete call moved there (its deletedAt). They count in totals and budgets again.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entryIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An entry id (from expenses.entries or expenses.add)"
                        }
                      },
                      "deletedAt": {
                        "description": "The deletedAt of an expenses.delete answer: brings back all it moved",
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "entryIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "day": { "type": "string", "format": "date" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency; null while the rate of its day is not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"],
                                "description": "same (no conversion), daily (that day’s rate), person (typed), pending"
                              },
                              "checkAmount": {
                                "type": "boolean",
                                "description": "Written by a recurring bill whose amount changes: check it"
                              },
                              "recurringId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The recurring bill or income that wrote it (expenses.recurring), if any"
                              },
                              "receiptIds": {
                                "type": "array",
                                "items": { "type": "string", "format": "uuid" },
                                "description": "Receipts attached to it (expenses.readReceipt reads one)"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "day",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateDay",
                              "rateSource",
                              "checkAmount",
                              "recurringId",
                              "receiptIds",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          },
                          "description": "The entries restored (at most the first 100)"
                        },
                        "count": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many came back"
                        }
                      },
                      "required": ["entries", "count"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.trash": {
      "post": {
        "operationId": "expenses.trash",
        "summary": "List the trash",
        "description": "Entries in the trash, most recently deleted first, with until when each can be restored. total is how many the trash holds; nextCursor reads the next page.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "description": "nextCursor from the previous page",
                        "type": "string"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "day": { "type": "string", "format": "date" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency; null while the rate of its day is not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"],
                                "description": "same (no conversion), daily (that day’s rate), person (typed), pending"
                              },
                              "checkAmount": {
                                "type": "boolean",
                                "description": "Written by a recurring bill whose amount changes: check it"
                              },
                              "recurringId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The recurring bill or income that wrote it (expenses.recurring), if any"
                              },
                              "receiptIds": {
                                "type": "array",
                                "items": { "type": "string", "format": "uuid" },
                                "description": "Receipts attached to it (expenses.readReceipt reads one)"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" },
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "day",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateDay",
                              "rateSource",
                              "checkAmount",
                              "recurringId",
                              "receiptIds",
                              "revision",
                              "createdAt",
                              "updatedAt",
                              "deletedAt",
                              "restoreUntil"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Entries in the trash, across every page"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["entries", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.deleteForever": {
      "post": {
        "operationId": "expenses.deleteForever",
        "summary": "Delete entries in the trash for good",
        "description": "Delete entries that are in the trash for good, with their receipts: the ones named (entryIds), or the whole trash (all: true), however big. It cannot be undone, so ask the person first. Entries not in the trash are refused: expenses.delete moves an entry there.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entryIds": {
                        "description": "Entries in the trash to delete for good (from expenses.trash)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "An entry id (from expenses.entries or expenses.add)"
                        }
                      },
                      "all": {
                        "description": "true: empty the whole trash instead",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "entryIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "entries": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many entries were deleted for good"
                        }
                      },
                      "required": ["entries"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.attachReceipt": {
      "post": {
        "operationId": "expenses.attachReceipt",
        "summary": "Attach a receipt",
        "description": "Store a photo or PDF of a receipt, on an entry or on its own. To log a receipt: attach it without entryId, read it with expenses.readReceipt, then log it with expenses.add and its receiptId (a receipt never logged is deleted after 7 days). Chat apps send small files (up to 5 MB) inline as base64 in data. Otherwise give size and sha256 (the CLI fills them from --file <path>): the answer has an upload link to PUT the bytes to, then call expenses.finishReceipt.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "entryId": {
                        "description": "The entry it belongs to, when it is already logged",
                        "type": "string",
                        "format": "uuid"
                      },
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 255,
                        "description": "File name, e.g. receipt.jpg"
                      },
                      "contentType": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 200,
                        "description": "A picture (image/jpeg, image/png, image/heic...) or application/pdf"
                      },
                      "data": {
                        "description": "The whole file as base64 (up to 5 MB): stored in one step",
                        "type": "string",
                        "maxLength": 6990508
                      },
                      "size": {
                        "description": "Bytes, when uploading with the link instead",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "sha256": {
                        "description": "Hex SHA-256 of the bytes, when uploading",
                        "type": "string"
                      }
                    },
                    "required": ["name", "contentType"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "name": "receipt.jpg",
                  "contentType": "image/jpeg",
                  "data": "/9j/4AAQSkZJRg=="
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "receipt": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "entryId": {
                              "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }],
                              "description": "The entry it belongs to; null until one is logged with it"
                            },
                            "name": { "type": "string" },
                            "contentType": { "type": "string" },
                            "size": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "status": {
                              "type": "string",
                              "enum": ["pending", "ready"],
                              "description": "pending until the upload is finished"
                            },
                            "read": {
                              "type": "string",
                              "enum": ["pending", "done", "none"],
                              "description": "Whether its text has been read yet (none: no readable text in it)"
                            }
                          },
                          "required": [
                            "id",
                            "entryId",
                            "name",
                            "contentType",
                            "size",
                            "status",
                            "read"
                          ]
                        },
                        "upload": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "url": { "type": "string", "format": "uri" },
                                "method": { "type": "string", "const": "PUT" },
                                "headers": {
                                  "type": "object",
                                  "propertyNames": { "type": "string" },
                                  "description": "Send exactly these headers with the bytes"
                                },
                                "expiresAt": { "type": "string", "format": "date-time" }
                              },
                              "required": ["url", "method", "headers", "expiresAt"]
                            },
                            { "type": "null" }
                          ]
                        },
                        "finish": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "operation": { "type": "string" },
                                "input": { "type": "object", "propertyNames": { "type": "string" } }
                              },
                              "required": ["operation", "input"]
                            },
                            { "type": "null" }
                          ],
                          "description": "After uploading, call this operation with this input (the CLI does it for you)"
                        }
                      },
                      "required": ["receipt", "upload", "finish"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.finishReceipt": {
      "post": {
        "operationId": "expenses.finishReceipt",
        "summary": "Finish attaching a receipt",
        "description": "Confirm a receipt after its bytes were uploaded with the link from attachReceipt.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "receiptId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A receipt id (from expenses.attachReceipt or an entry)"
                      }
                    },
                    "required": ["receiptId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "receiptId": "01a1927a-1071-7a71-994f-4180839c9a39" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "receipt": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "entryId": {
                              "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }],
                              "description": "The entry it belongs to; null until one is logged with it"
                            },
                            "name": { "type": "string" },
                            "contentType": { "type": "string" },
                            "size": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "status": {
                              "type": "string",
                              "enum": ["pending", "ready"],
                              "description": "pending until the upload is finished"
                            },
                            "read": {
                              "type": "string",
                              "enum": ["pending", "done", "none"],
                              "description": "Whether its text has been read yet (none: no readable text in it)"
                            }
                          },
                          "required": [
                            "id",
                            "entryId",
                            "name",
                            "contentType",
                            "size",
                            "status",
                            "read"
                          ]
                        }
                      },
                      "required": ["receipt"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.readReceipt": {
      "post": {
        "operationId": "expenses.readReceipt",
        "summary": "Read a receipt",
        "description": "The text read out of a receipt (words in the photo, or the PDF text), plain guesses of its total, day, currency and shop, and a short link to view it. Text is read a few seconds after upload; until then the answer says so. Check the guesses against the text before logging.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "receiptId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A receipt id (from expenses.attachReceipt or an entry)"
                      }
                    },
                    "required": ["receiptId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "receiptId": "01a1927a-1071-7a71-994f-4180839c9a39" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "receipt": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "entryId": {
                              "anyOf": [{ "type": "string", "format": "uuid" }, { "type": "null" }],
                              "description": "The entry it belongs to; null until one is logged with it"
                            },
                            "name": { "type": "string" },
                            "contentType": { "type": "string" },
                            "size": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "status": {
                              "type": "string",
                              "enum": ["pending", "ready"],
                              "description": "pending until the upload is finished"
                            },
                            "read": {
                              "type": "string",
                              "enum": ["pending", "done", "none"],
                              "description": "Whether its text has been read yet (none: no readable text in it)"
                            }
                          },
                          "required": [
                            "id",
                            "entryId",
                            "name",
                            "contentType",
                            "size",
                            "status",
                            "read"
                          ]
                        },
                        "text": {
                          "description": "null until it is read, or when nothing was readable",
                          "type": ["string", "null"]
                        },
                        "textCut": {
                          "type": "boolean",
                          "description": "True when the text was too long and was cut"
                        },
                        "guesses": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "total": {
                                  "anyOf": [
                                    {
                                      "type": "object",
                                      "properties": {
                                        "amount": { "type": "number" },
                                        "line": { "type": "string" }
                                      },
                                      "required": ["amount", "line"]
                                    },
                                    { "type": "null" }
                                  ],
                                  "description": "The amount on the line that looks most like the total to pay"
                                },
                                "day": {
                                  "anyOf": [
                                    {
                                      "type": "object",
                                      "properties": {
                                        "value": { "type": "string", "format": "date" },
                                        "alternative": {
                                          "anyOf": [
                                            { "type": "string", "format": "date" },
                                            { "type": "null" }
                                          ],
                                          "description": "The other reading of a date like 03/04"
                                        },
                                        "line": { "type": "string" }
                                      },
                                      "required": ["value", "alternative", "line"]
                                    },
                                    { "type": "null" }
                                  ]
                                },
                                "currency": {
                                  "description": "The currency shown most ($ is read as USD)",
                                  "type": ["string", "null"]
                                },
                                "merchant": {
                                  "description": "The first line near the top that reads like a name",
                                  "type": ["string", "null"]
                                }
                              },
                              "required": ["total", "day", "currency", "merchant"]
                            },
                            { "type": "null" }
                          ]
                        },
                        "url": {
                          "anyOf": [{ "type": "string", "format": "uri" }, { "type": "null" }],
                          "description": "A short-lived link to view the receipt (5 minutes)"
                        },
                        "downloadUrl": {
                          "anyOf": [{ "type": "string", "format": "uri" }, { "type": "null" }],
                          "description": "A short-lived link that saves the receipt as a file (5 minutes)"
                        },
                        "next": { "type": "string", "description": "What to do next" }
                      },
                      "required": [
                        "receipt",
                        "text",
                        "textCut",
                        "guesses",
                        "url",
                        "downloadUrl",
                        "next"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.removeReceipt": {
      "post": {
        "operationId": "expenses.removeReceipt",
        "summary": "Delete a receipt",
        "description": "Delete a receipt file for good. The entry it was on stays. This cannot be undone.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "receiptId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A receipt id (from expenses.attachReceipt or an entry)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["receiptId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "receiptId": "01a1927a-1071-7a71-994f-4180839c9a39" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean" }
                      },
                      "required": ["id", "deleted"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.recurring": {
      "post": {
        "operationId": "expenses.recurring",
        "summary": "List recurring bills and income",
        "description": "The recurring bills and income (rent, phone, salary...), each with how often it comes back and the next day its entry is written.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "recurring": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "kind": { "type": "string", "enum": ["spending", "income"] },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "category": { "type": "string" },
                              "categoryId": { "type": "string", "format": "uuid" },
                              "merchant": { "type": "string" },
                              "note": { "type": "string" },
                              "variable": {
                                "type": "boolean",
                                "description": "The amount changes: each entry repeats the last one, flagged"
                              },
                              "repeat": {
                                "type": "object",
                                "properties": {
                                  "repeat": {
                                    "type": "string",
                                    "enum": ["weekly", "monthly", "yearly"],
                                    "description": "weekly, monthly or yearly"
                                  },
                                  "every": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  "dayOfMonth": {
                                    "anyOf": [
                                      {
                                        "anyOf": [
                                          { "type": "integer", "minimum": 1, "maximum": 31 },
                                          { "type": "string", "const": "last" }
                                        ],
                                        "description": "Monthly: the day of the month, or last (29-31 fall on the last day of shorter months); default: the day of starts"
                                      },
                                      { "type": "null" }
                                    ]
                                  },
                                  "weekday": {
                                    "anyOf": [
                                      {
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 7,
                                        "description": "Weekly: 1 = Monday ... 7 = Sunday; default: the weekday of starts"
                                      },
                                      { "type": "null" }
                                    ]
                                  },
                                  "starts": { "type": "string", "format": "date" },
                                  "until": {
                                    "anyOf": [
                                      { "type": "string", "format": "date" },
                                      { "type": "null" }
                                    ]
                                  }
                                },
                                "required": [
                                  "repeat",
                                  "every",
                                  "dayOfMonth",
                                  "weekday",
                                  "starts",
                                  "until"
                                ]
                              },
                              "nextDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ],
                                "description": "The next day an entry is written; null once ended"
                              },
                              "paused": { "type": "boolean" },
                              "skipDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ],
                                "description": "One day that will be skipped"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              }
                            },
                            "required": [
                              "id",
                              "kind",
                              "amount",
                              "currency",
                              "category",
                              "categoryId",
                              "merchant",
                              "note",
                              "variable",
                              "repeat",
                              "nextDay",
                              "paused",
                              "skipDay",
                              "revision"
                            ]
                          }
                        }
                      },
                      "required": ["recurring"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.addRecurring": {
      "post": {
        "operationId": "expenses.addRecurring",
        "summary": "Add a recurring bill or income",
        "description": "A bill or income that comes back (rent on the 1st, salary on the 25th, a weekly class). From the next matching day on, its entry is written by itself each time, in the morning of the person’s time zone. For a bill whose amount changes (electricity), set variable: each entry repeats the last amount and is flagged checkAmount so the person can correct it.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "note": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 500,
                        "description": "What it is, e.g. Rent (written as each entry’s note)"
                      },
                      "amount": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1000000000000,
                        "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                      },
                      "currency": {
                        "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                        "type": "string"
                      },
                      "kind": {
                        "default": "spending",
                        "type": "string",
                        "enum": ["spending", "income"],
                        "description": "spending (money out, the default) or income (money in)"
                      },
                      "category": {
                        "description": "A category name (default: Other)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "merchant": { "default": "", "type": "string", "maxLength": 120 },
                      "variable": {
                        "default": false,
                        "description": "The amount changes each time",
                        "type": "boolean"
                      },
                      "repeat": {
                        "default": "monthly",
                        "type": "string",
                        "enum": ["weekly", "monthly", "yearly"],
                        "description": "weekly, monthly or yearly"
                      },
                      "every": {
                        "default": 1,
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 12,
                        "description": "Every N weeks, months or years (default 1)"
                      },
                      "dayOfMonth": {
                        "anyOf": [
                          { "type": "integer", "minimum": 1, "maximum": 31 },
                          { "type": "string", "const": "last" }
                        ],
                        "description": "Monthly: the day of the month, or last (29-31 fall on the last day of shorter months); default: the day of starts"
                      },
                      "weekday": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 7,
                        "description": "Weekly: 1 = Monday ... 7 = Sunday; default: the weekday of starts"
                      },
                      "starts": {
                        "type": "string",
                        "format": "date",
                        "description": "The first day it can happen (default: today)"
                      },
                      "until": {
                        "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                        "description": "The last day it can happen (null: no end)"
                      },
                      "addMissingCategories": {
                        "default": false,
                        "description": "Make the category if it does not exist yet instead of refusing it",
                        "type": "boolean"
                      }
                    },
                    "required": ["note", "amount"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "note": "Rent", "amount": 4500, "category": "Home", "dayOfMonth": 1 }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "recurring": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "kind": { "type": "string", "enum": ["spending", "income"] },
                            "amount": { "type": "number" },
                            "currency": { "type": "string" },
                            "category": { "type": "string" },
                            "categoryId": { "type": "string", "format": "uuid" },
                            "merchant": { "type": "string" },
                            "note": { "type": "string" },
                            "variable": {
                              "type": "boolean",
                              "description": "The amount changes: each entry repeats the last one, flagged"
                            },
                            "repeat": {
                              "type": "object",
                              "properties": {
                                "repeat": {
                                  "type": "string",
                                  "enum": ["weekly", "monthly", "yearly"],
                                  "description": "weekly, monthly or yearly"
                                },
                                "every": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "dayOfMonth": {
                                  "anyOf": [
                                    {
                                      "anyOf": [
                                        { "type": "integer", "minimum": 1, "maximum": 31 },
                                        { "type": "string", "const": "last" }
                                      ],
                                      "description": "Monthly: the day of the month, or last (29-31 fall on the last day of shorter months); default: the day of starts"
                                    },
                                    { "type": "null" }
                                  ]
                                },
                                "weekday": {
                                  "anyOf": [
                                    {
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 7,
                                      "description": "Weekly: 1 = Monday ... 7 = Sunday; default: the weekday of starts"
                                    },
                                    { "type": "null" }
                                  ]
                                },
                                "starts": { "type": "string", "format": "date" },
                                "until": {
                                  "anyOf": [
                                    { "type": "string", "format": "date" },
                                    { "type": "null" }
                                  ]
                                }
                              },
                              "required": [
                                "repeat",
                                "every",
                                "dayOfMonth",
                                "weekday",
                                "starts",
                                "until"
                              ]
                            },
                            "nextDay": {
                              "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                              "description": "The next day an entry is written; null once ended"
                            },
                            "paused": { "type": "boolean" },
                            "skipDay": {
                              "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                              "description": "One day that will be skipped"
                            },
                            "revision": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            }
                          },
                          "required": [
                            "id",
                            "kind",
                            "amount",
                            "currency",
                            "category",
                            "categoryId",
                            "merchant",
                            "note",
                            "variable",
                            "repeat",
                            "nextDay",
                            "paused",
                            "skipDay",
                            "revision"
                          ]
                        },
                        "homeCurrency": { "type": "string" },
                        "homeCurrencySet": {
                          "type": "boolean",
                          "description": "True when this call set the home currency"
                        }
                      },
                      "required": ["recurring", "homeCurrency", "homeCurrencySet"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.updateRecurring": {
      "post": {
        "operationId": "expenses.updateRecurring",
        "summary": "Change a recurring bill or income",
        "description": "Change a recurring bill or income: its amount, currency, category, merchant, note, whether the amount varies, how often it comes back, or pause it (paused: true, false to resume). skipDay skips one day only (its nextDay from expenses.recurring, to skip the next one; null cancels). Entries already written stay as they are. Only what is given changes.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "recurringId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A recurring bill or income id (from expenses.recurring)"
                      },
                      "revision": {
                        "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      "note": { "type": "string", "minLength": 1, "maxLength": 500 },
                      "amount": {
                        "type": "number",
                        "exclusiveMinimum": 0,
                        "maximum": 1000000000000,
                        "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                      },
                      "currency": {
                        "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                        "type": "string"
                      },
                      "category": { "type": "string", "minLength": 1, "maxLength": 60 },
                      "merchant": { "type": "string", "maxLength": 120 },
                      "variable": { "type": "boolean" },
                      "paused": {
                        "description": "Stop writing entries (false: start again)",
                        "type": "boolean"
                      },
                      "skipDay": {
                        "description": "One day to skip; null cancels it",
                        "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }]
                      },
                      "repeat": {
                        "type": "string",
                        "enum": ["weekly", "monthly", "yearly"],
                        "description": "weekly, monthly or yearly"
                      },
                      "every": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 12,
                        "description": "Every N weeks, months or years (default 1)"
                      },
                      "dayOfMonth": {
                        "anyOf": [
                          {
                            "anyOf": [
                              { "type": "integer", "minimum": 1, "maximum": 31 },
                              { "type": "string", "const": "last" }
                            ],
                            "description": "Monthly: the day of the month, or last (29-31 fall on the last day of shorter months); default: the day of starts"
                          },
                          { "type": "null" }
                        ]
                      },
                      "weekday": {
                        "anyOf": [
                          {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 7,
                            "description": "Weekly: 1 = Monday ... 7 = Sunday; default: the weekday of starts"
                          },
                          { "type": "null" }
                        ]
                      },
                      "starts": {
                        "type": "string",
                        "format": "date",
                        "description": "The first day it can happen (default: today)"
                      },
                      "until": {
                        "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                        "description": "The last day it can happen (null: no end)"
                      },
                      "addMissingCategories": { "default": false, "type": "boolean" }
                    },
                    "required": ["recurringId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "recurringId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "amount": 4800 }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "recurring": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "kind": { "type": "string", "enum": ["spending", "income"] },
                            "amount": { "type": "number" },
                            "currency": { "type": "string" },
                            "category": { "type": "string" },
                            "categoryId": { "type": "string", "format": "uuid" },
                            "merchant": { "type": "string" },
                            "note": { "type": "string" },
                            "variable": {
                              "type": "boolean",
                              "description": "The amount changes: each entry repeats the last one, flagged"
                            },
                            "repeat": {
                              "type": "object",
                              "properties": {
                                "repeat": {
                                  "type": "string",
                                  "enum": ["weekly", "monthly", "yearly"],
                                  "description": "weekly, monthly or yearly"
                                },
                                "every": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "dayOfMonth": {
                                  "anyOf": [
                                    {
                                      "anyOf": [
                                        { "type": "integer", "minimum": 1, "maximum": 31 },
                                        { "type": "string", "const": "last" }
                                      ],
                                      "description": "Monthly: the day of the month, or last (29-31 fall on the last day of shorter months); default: the day of starts"
                                    },
                                    { "type": "null" }
                                  ]
                                },
                                "weekday": {
                                  "anyOf": [
                                    {
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 7,
                                      "description": "Weekly: 1 = Monday ... 7 = Sunday; default: the weekday of starts"
                                    },
                                    { "type": "null" }
                                  ]
                                },
                                "starts": { "type": "string", "format": "date" },
                                "until": {
                                  "anyOf": [
                                    { "type": "string", "format": "date" },
                                    { "type": "null" }
                                  ]
                                }
                              },
                              "required": [
                                "repeat",
                                "every",
                                "dayOfMonth",
                                "weekday",
                                "starts",
                                "until"
                              ]
                            },
                            "nextDay": {
                              "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                              "description": "The next day an entry is written; null once ended"
                            },
                            "paused": { "type": "boolean" },
                            "skipDay": {
                              "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }],
                              "description": "One day that will be skipped"
                            },
                            "revision": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            }
                          },
                          "required": [
                            "id",
                            "kind",
                            "amount",
                            "currency",
                            "category",
                            "categoryId",
                            "merchant",
                            "note",
                            "variable",
                            "repeat",
                            "nextDay",
                            "paused",
                            "skipDay",
                            "revision"
                          ]
                        }
                      },
                      "required": ["recurring"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/expenses.removeRecurring": {
      "post": {
        "operationId": "expenses.removeRecurring",
        "summary": "Remove a recurring bill or income",
        "description": "Stop a recurring bill or income for good (to stop it for a while, pause it with expenses.updateRecurring). The entries it already wrote stay. Ask the person first.",
        "tags": ["expenses"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "recurringId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A recurring bill or income id (from expenses.recurring)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["recurringId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "recurringId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": { "removed": { "type": "string", "format": "uuid" } },
                      "required": ["removed"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.add": {
      "post": {
        "operationId": "debts.add",
        "summary": "Record money lent or borrowed",
        "description": "Record up to 100 debts in one call. Each has a person (a saved name, see debts.people), a way (theyOwe: they owe me; iOwe: I owe them), an amount, a currency (default: the home currency), a day (default: today), an optional due day and note. Paybacks go through debts.payBack, never a new debt the other way. Lending is not spending: nothing is logged in expenses. If the person has no home currency yet, the first currency given becomes it; say so.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debts": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "person": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 60,
                              "description": "A saved name, exactly. If the name given is close to saved ones but not the same, ask which person they mean instead of choosing one."
                            },
                            "way": {
                              "type": "string",
                              "enum": ["theyOwe", "iOwe"],
                              "description": "theyOwe: the person owes me (I lent). iOwe: I owe the person (I borrowed)."
                            },
                            "amount": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000000,
                              "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                            },
                            "currency": {
                              "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "dueDay": {
                              "type": "string",
                              "format": "date",
                              "description": "The day it should be paid back by (an event fires that day)"
                            },
                            "note": { "default": "", "type": "string", "maxLength": 500 },
                            "rate": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000,
                              "description": "The rate really used: units of the home currency per one unit of this currency. Without it, the stored rate of that day is used."
                            }
                          },
                          "required": ["person", "way", "amount"]
                        }
                      },
                      "addMissingPeople": {
                        "default": false,
                        "description": "Add people who are not saved yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["debts"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "debts": [
                    {
                      "person": "Nadia",
                      "way": "theyOwe",
                      "amount": 500,
                      "note": "Concert tickets"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "homeCurrency": { "type": "string" },
                        "homeCurrencySet": {
                          "type": "boolean",
                          "description": "True when this call set the home currency (tell the person)"
                        }
                      },
                      "required": ["debts", "homeCurrency", "homeCurrencySet"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.update": {
      "post": {
        "operationId": "debts.update",
        "summary": "Change debts",
        "description": "Change up to 100 debts: person, way, amount, currency, day, due day (null clears it), note, or the rate really used (null goes back to the day’s stored rate). Only what is given changes. A payback is not a change: use debts.payBack.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debts": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "debtId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A debt id (from debts.list or debts.add)"
                            },
                            "revision": {
                              "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 9007199254740991
                            },
                            "person": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 60,
                              "description": "A saved name, exactly. If the name given is close to saved ones but not the same, ask which person they mean instead of choosing one."
                            },
                            "way": {
                              "type": "string",
                              "enum": ["theyOwe", "iOwe"],
                              "description": "theyOwe: the person owes me (I lent). iOwe: I owe the person (I borrowed)."
                            },
                            "amount": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000000,
                              "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                            },
                            "currency": {
                              "description": "A three-letter currency code (ISO 4217), e.g. MAD, USD, EUR, GBP. A currency named without its country is the home currency when the names match; otherwise ask which one.",
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "dueDay": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "format": "date",
                                  "description": "The day it should be paid back by (an event fires that day)"
                                },
                                { "type": "null" }
                              ]
                            },
                            "note": { "type": "string", "maxLength": 500 },
                            "rate": {
                              "anyOf": [
                                {
                                  "type": "number",
                                  "exclusiveMinimum": 0,
                                  "maximum": 1000000000,
                                  "description": "The rate really used: units of the home currency per one unit of this currency. Without it, the stored rate of that day is used."
                                },
                                { "type": "null" }
                              ]
                            }
                          },
                          "required": ["debtId"]
                        }
                      },
                      "addMissingPeople": {
                        "default": false,
                        "description": "Add people who are not saved yet instead of refusing them",
                        "type": "boolean"
                      }
                    },
                    "required": ["debts"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "debts": [{ "debtId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "amount": 450 }]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        }
                      },
                      "required": ["debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.list": {
      "post": {
        "operationId": "debts.list",
        "summary": "List or search debts",
        "description": "Debts with their paybacks, newest first (or oldest first), filtered by person, way, status (open by default), due days, currency, words in the note or ids. For who owes what in total use debts.balances instead of adding up pages.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "person": {
                        "description": "Only this person (a saved name)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "personId": {
                        "description": "Only this person, by id",
                        "type": "string",
                        "format": "uuid"
                      },
                      "way": {
                        "type": "string",
                        "enum": ["theyOwe", "iOwe"],
                        "description": "theyOwe: the person owes me (I lent). iOwe: I owe the person (I borrowed)."
                      },
                      "status": {
                        "default": "open",
                        "description": "open (default), closed or all",
                        "type": "string",
                        "enum": ["open", "closed", "all"]
                      },
                      "dueAfter": {
                        "description": "Only debts due on or after this day",
                        "type": "string",
                        "format": "date"
                      },
                      "dueBefore": {
                        "description": "Only debts due on or before this day",
                        "type": "string",
                        "format": "date"
                      },
                      "currency": {
                        "description": "Only debts in this currency",
                        "type": "string"
                      },
                      "query": {
                        "description": "Words in the note",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "debtIds": {
                        "description": "Only these debts, by id (with status all to find closed ones too)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A debt id (from debts.list or debts.add)"
                        }
                      },
                      "order": {
                        "default": "newest",
                        "description": "newest first (default) or oldest first, by day",
                        "type": "string",
                        "enum": ["newest", "oldest"]
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "person": "Nadia" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many debts match, over every page"
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "homeCurrency": { "type": ["string", "null"] },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Debts whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": [
                        "debts",
                        "total",
                        "nextCursor",
                        "homeCurrency",
                        "waitingForRates"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.balances": {
      "post": {
        "operationId": "debts.balances",
        "summary": "Who owes what",
        "description": "What each person still owes me and what I still owe them, and the difference, over open debts, in the home currency (each debt at the rate of its day), plus the totals. One call answers how much one person owes, or who still owes money.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "person": {
                        "description": "Only this person (a saved name)",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "theyOwe": { "type": "number", "description": "What they still owe me" },
                        "iOwe": { "type": "number", "description": "What I still owe them" },
                        "net": {
                          "type": "number",
                          "description": "theyOwe minus iOwe: above zero, they owe me overall"
                        },
                        "openDebts": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "currency": {
                          "description": "The home currency the balances are in",
                          "type": ["string", "null"]
                        },
                        "people": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "theyOwe": {
                                "type": "number",
                                "description": "What they still owe me"
                              },
                              "iOwe": { "type": "number", "description": "What I still owe them" },
                              "net": {
                                "type": "number",
                                "description": "theyOwe minus iOwe: above zero, they owe me overall"
                              },
                              "openDebts": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "nextDueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ],
                                "description": "The earliest due day of their open debts"
                              }
                            },
                            "required": [
                              "theyOwe",
                              "iOwe",
                              "net",
                              "openDebts",
                              "person",
                              "personId",
                              "nextDueDay"
                            ]
                          }
                        },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Debts whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": [
                        "theyOwe",
                        "iOwe",
                        "net",
                        "openDebts",
                        "currency",
                        "people",
                        "waitingForRates"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.balanceHistory": {
      "post": {
        "operationId": "debts.balanceHistory",
        "summary": "Who owed what on past days",
        "description": "Where things stood at the end of past days: what was still owed to me, what I still owed, and the difference. Give up to 12 days, such as month ends; amounts are in the home currency, each debt at the rate of its day, and a closed debt counts until the day it closed. For today use debts.balances.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "days": {
                        "minItems": 1,
                        "maxItems": 12,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "date",
                          "description": "A day, as YYYY-MM-DD"
                        },
                        "description": "The days to answer for, oldest first or in any order"
                      }
                    },
                    "required": ["days"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "days": ["2026-09-30", "2026-10-31"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "currency": {
                          "description": "The home currency the amounts are in",
                          "type": ["string", "null"]
                        },
                        "points": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "day": { "type": "string", "format": "date" },
                              "theyOwe": {
                                "type": "number",
                                "description": "What they still owed me at the end of the day"
                              },
                              "iOwe": {
                                "type": "number",
                                "description": "What I still owed them at the end of the day"
                              },
                              "net": {
                                "type": "number",
                                "description": "theyOwe minus iOwe: above zero, they owed me overall"
                              }
                            },
                            "required": ["day", "theyOwe", "iOwe", "net"]
                          },
                          "description": "One per day asked, oldest first"
                        },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Debts whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": ["currency", "points", "waitingForRates"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.history": {
      "post": {
        "operationId": "debts.history",
        "summary": "What happened with a person",
        "description": "Everything that happened on the debts with one person, newest first: money lent or borrowed, each payback, and what was forgiven. Debts in the trash are left out.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "personId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A person id (from debts.people)"
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    },
                    "required": ["personId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "personId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "day": { "type": "string", "format": "date" },
                              "kind": {
                                "type": "string",
                                "enum": ["lent", "borrowed", "paidBack", "youPaid", "forgiven"],
                                "description": "lent or borrowed (the debt was made), paidBack (they paid me), youPaid (I paid them), forgiven (what was left was let go)"
                              },
                              "debtId": { "type": "string", "format": "uuid" },
                              "paybackId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "The payback, for paidBack and youPaid"
                              },
                              "note": { "type": "string", "description": "The debt’s note" },
                              "amount": {
                                "type": "number",
                                "description": "In the debt’s currency"
                              },
                              "currency": { "type": "string" },
                              "homeAmount": {
                                "description": "The same in the home currency; null until known",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" }
                            },
                            "required": [
                              "day",
                              "kind",
                              "debtId",
                              "paybackId",
                              "note",
                              "amount",
                              "currency",
                              "homeAmount",
                              "homeCurrency"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many events there are, over every page"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["events", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.payBack": {
      "post": {
        "operationId": "debts.payBack",
        "summary": "Record a payback",
        "description": "Record money paid back, in part or in full, by them or by me. Name the debt (debtId) or the person; with a person, it goes to their oldest open debts first (the answer says which), the way given (theyOwe: they paid me; iOwe: I paid them; needed only when debts go both ways). The amount is in the debt’s currency and can never be more than what is left (refused with what is left). A debt closes by itself when nothing is left.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "paybacks": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "debtId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A debt id (from debts.list or debts.add)"
                            },
                            "person": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 60,
                              "description": "A saved name, exactly. If the name given is close to saved ones but not the same, ask which person they mean instead of choosing one."
                            },
                            "way": {
                              "type": "string",
                              "enum": ["theyOwe", "iOwe"],
                              "description": "theyOwe: the person owes me (I lent). iOwe: I owe the person (I borrowed)."
                            },
                            "amount": {
                              "type": "number",
                              "exclusiveMinimum": 0,
                              "maximum": 1000000000000,
                              "description": "How much, in the currency’s normal units (45.5 means 45.50), always positive"
                            },
                            "currency": {
                              "description": "The debt’s currency (default: that of the oldest open debt)",
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "format": "date",
                              "description": "A day, as YYYY-MM-DD"
                            },
                            "note": { "default": "", "type": "string", "maxLength": 500 }
                          },
                          "required": ["amount"]
                        }
                      }
                    },
                    "required": ["paybacks"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "paybacks": [{ "person": "Nadia", "amount": 200 }] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "recorded": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "paybackId": { "type": "string", "format": "uuid" },
                              "debtId": { "type": "string", "format": "uuid" },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" }
                            },
                            "required": ["paybackId", "debtId", "amount", "currency"]
                          }
                        },
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          },
                          "description": "The debts paid back on, as they are now"
                        }
                      },
                      "required": ["recorded", "debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.removePayback": {
      "post": {
        "operationId": "debts.removePayback",
        "summary": "Remove a payback",
        "description": "Remove a payback recorded by mistake, for good. Its debt owes that amount again, and reopens if it had closed as paid.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "paybackId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A payback id (from a debt’s paybacks)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["paybackId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "paybackId": "01a1927a-1071-7a71-994f-4180839c9a39" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debt": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "person": { "type": "string" },
                            "personId": { "type": "string", "format": "uuid" },
                            "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                            "amount": {
                              "type": "number",
                              "description": "The amount lent or borrowed, in currency"
                            },
                            "currency": { "type": "string" },
                            "paid": {
                              "type": "number",
                              "description": "Paid back so far, in currency"
                            },
                            "left": {
                              "type": "number",
                              "description": "Still owed, in currency (0 once closed)"
                            },
                            "homeAmount": {
                              "description": "The amount in the home currency at the rate of its day; null while not in yet",
                              "type": ["number", "null"]
                            },
                            "homeCurrency": { "type": "string" },
                            "rate": {
                              "description": "Units of the home currency per one unit of currency",
                              "type": ["number", "null"]
                            },
                            "rateSource": {
                              "type": "string",
                              "enum": ["same", "daily", "person", "pending"]
                            },
                            "day": { "type": "string", "format": "date" },
                            "dueDay": {
                              "anyOf": [{ "type": "string", "format": "date" }, { "type": "null" }]
                            },
                            "note": { "type": "string" },
                            "status": {
                              "type": "string",
                              "enum": ["open", "paid", "forgiven"],
                              "description": "open, paid (in full) or forgiven"
                            },
                            "closedAt": {
                              "anyOf": [
                                { "type": "string", "format": "date-time" },
                                { "type": "null" }
                              ]
                            },
                            "paybacks": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "format": "uuid" },
                                  "amount": { "type": "number" },
                                  "day": { "type": "string", "format": "date" },
                                  "note": { "type": "string" }
                                },
                                "required": ["id", "amount", "day", "note"]
                              },
                              "description": "Oldest first"
                            },
                            "revision": {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            "createdAt": { "type": "string", "format": "date-time" },
                            "updatedAt": { "type": "string", "format": "date-time" }
                          },
                          "required": [
                            "id",
                            "person",
                            "personId",
                            "way",
                            "amount",
                            "currency",
                            "paid",
                            "left",
                            "homeAmount",
                            "homeCurrency",
                            "rate",
                            "rateSource",
                            "day",
                            "dueDay",
                            "note",
                            "status",
                            "closedAt",
                            "paybacks",
                            "revision",
                            "createdAt",
                            "updatedAt"
                          ]
                        }
                      },
                      "required": ["debt"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.forgive": {
      "post": {
        "operationId": "debts.forgive",
        "summary": "Forgive debts",
        "description": "Close open debts without full payback; they stay listed as forgiven with their paybacks. undo: true reopens forgiven ones.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debtIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A debt id (from debts.list or debts.add)"
                        }
                      },
                      "undo": { "default": false, "type": "boolean" }
                    },
                    "required": ["debtIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "debtIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        }
                      },
                      "required": ["debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.people": {
      "post": {
        "operationId": "debts.people",
        "summary": "List people",
        "description": "The people debts are with (names only, never HeyBMO accounts), with where you stand with each in the home currency: people with open debts first, the biggest difference first, then by name. Each has the earliest due day of their open debts. Search by name with query; open keeps only people with open debts. Archived people are left out unless archived is include or only. Use these names when recording debts and paybacks.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "query": {
                        "description": "Letters in the name",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "archived": {
                        "default": "hide",
                        "description": "hide archived people (default), include them, or only them",
                        "type": "string",
                        "enum": ["hide", "include", "only"]
                      },
                      "personId": {
                        "description": "Only this person",
                        "type": "string",
                        "format": "uuid"
                      },
                      "open": {
                        "default": false,
                        "description": "true: only people with open debts",
                        "type": "boolean"
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "people": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "archived": { "type": "boolean" },
                              "theyOwe": {
                                "type": "number",
                                "description": "What they still owe me, in the home currency"
                              },
                              "iOwe": {
                                "type": "number",
                                "description": "What I still owe them, in the home currency"
                              },
                              "net": {
                                "type": "number",
                                "description": "theyOwe minus iOwe: above zero, they owe me overall"
                              },
                              "openDebts": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "nextDueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ],
                                "description": "The earliest due day of their open debts"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "archived",
                              "theyOwe",
                              "iOwe",
                              "net",
                              "openDebts",
                              "nextDueDay"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many people match, over every page"
                        },
                        "archived": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many people are archived in all"
                        },
                        "currency": {
                          "description": "The home currency the money is in",
                          "type": ["string", "null"]
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "waitingForRates": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Debts whose day’s rate is not in yet: not counted in home-currency amounts yet"
                        }
                      },
                      "required": [
                        "people",
                        "total",
                        "archived",
                        "currency",
                        "nextCursor",
                        "waitingForRates"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.addPerson": {
      "post": {
        "operationId": "debts.addPerson",
        "summary": "Add a person",
        "description": "Save someone debts can be with. debts.add can also add people as it records (addMissingPeople).",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 60 } },
                    "required": ["name"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "name": "Lina" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "archived": { "type": "boolean" }
                      },
                      "required": ["id", "name", "archived"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.updatePerson": {
      "post": {
        "operationId": "debts.updatePerson",
        "summary": "Rename or archive a person",
        "description": "Rename a person (their debts follow) or archive them: no longer offered, their debts kept. archived: false brings them back. Two names for the same person: debts.mergePeople.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "personId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A person id (from debts.people)"
                      },
                      "name": { "type": "string", "minLength": 1, "maxLength": 60 },
                      "archived": { "type": "boolean" }
                    },
                    "required": ["personId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "personId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "name": "Nadia" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "archived": { "type": "boolean" }
                      },
                      "required": ["id", "name", "archived"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.mergePeople": {
      "post": {
        "operationId": "debts.mergePeople",
        "summary": "Merge two names for one person",
        "description": "When two saved names turn out to be the same person: every debt of personId moves to intoPersonId, then personId is removed. Check with the person first: names that only look alike are often different people.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "personId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The name to remove (its debts move)"
                      },
                      "intoPersonId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "The name to keep"
                      }
                    },
                    "required": ["personId", "intoPersonId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "personId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                  "intoPersonId": "01a1927a-1071-7a71-994f-4180839c9a39"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "person": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "name": { "type": "string" },
                            "archived": { "type": "boolean" }
                          },
                          "required": ["id", "name", "archived"]
                        },
                        "debtsMoved": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["person", "debtsMoved"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.delete": {
      "post": {
        "operationId": "debts.delete",
        "summary": "Move debts to the trash",
        "description": "Move debts (with their paybacks) to the trash. They no longer count in balances, and can be restored with debts.restore for 30 days, then they are deleted for good. To close a debt without payback, use debts.forgive instead.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debtIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A debt id (from debts.list or debts.add)"
                        }
                      }
                    },
                    "required": ["debtIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "debtIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "deleted": {
                          "type": "array",
                          "items": { "type": "string", "format": "uuid" }
                        },
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" }
                      },
                      "required": ["deleted", "deletedAt", "restoreUntil"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.restore": {
      "post": {
        "operationId": "debts.restore",
        "summary": "Restore debts from the trash",
        "description": "Bring debts back from the trash; they count in balances again.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debtIds": {
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A debt id (from debts.list or debts.add)"
                        }
                      }
                    },
                    "required": ["debtIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "debtIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "personId": { "type": "string", "format": "uuid" },
                              "way": { "type": "string", "enum": ["theyOwe", "iOwe"] },
                              "amount": {
                                "type": "number",
                                "description": "The amount lent or borrowed, in currency"
                              },
                              "currency": { "type": "string" },
                              "paid": {
                                "type": "number",
                                "description": "Paid back so far, in currency"
                              },
                              "left": {
                                "type": "number",
                                "description": "Still owed, in currency (0 once closed)"
                              },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null while not in yet",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": "string" },
                              "rate": {
                                "description": "Units of the home currency per one unit of currency",
                                "type": ["number", "null"]
                              },
                              "rateSource": {
                                "type": "string",
                                "enum": ["same", "daily", "person", "pending"]
                              },
                              "day": { "type": "string", "format": "date" },
                              "dueDay": {
                                "anyOf": [
                                  { "type": "string", "format": "date" },
                                  { "type": "null" }
                                ]
                              },
                              "note": { "type": "string" },
                              "status": {
                                "type": "string",
                                "enum": ["open", "paid", "forgiven"],
                                "description": "open, paid (in full) or forgiven"
                              },
                              "closedAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "paybacks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": { "type": "string", "format": "uuid" },
                                    "amount": { "type": "number" },
                                    "day": { "type": "string", "format": "date" },
                                    "note": { "type": "string" }
                                  },
                                  "required": ["id", "amount", "day", "note"]
                                },
                                "description": "Oldest first"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "updatedAt": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "personId",
                              "way",
                              "amount",
                              "currency",
                              "paid",
                              "left",
                              "homeAmount",
                              "homeCurrency",
                              "rate",
                              "rateSource",
                              "day",
                              "dueDay",
                              "note",
                              "status",
                              "closedAt",
                              "paybacks",
                              "revision",
                              "createdAt",
                              "updatedAt"
                            ]
                          }
                        }
                      },
                      "required": ["debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.trash": {
      "post": {
        "operationId": "debts.trash",
        "summary": "List the trash",
        "description": "Debts in the trash, most recently deleted first, with until when each can be restored. Pass nextCursor back as cursor for the next page.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "description": "nextCursor from the previous page",
                        "type": "string"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "person": { "type": "string" },
                              "way": { "type": "string" },
                              "amount": { "type": "number" },
                              "currency": { "type": "string" },
                              "homeAmount": {
                                "description": "The amount in the home currency at the rate of its day; null until known",
                                "type": ["number", "null"]
                              },
                              "homeCurrency": { "type": ["string", "null"] },
                              "day": { "type": "string", "format": "date" },
                              "note": { "type": "string" },
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" }
                            },
                            "required": [
                              "id",
                              "person",
                              "way",
                              "amount",
                              "currency",
                              "homeAmount",
                              "homeCurrency",
                              "day",
                              "note",
                              "deletedAt",
                              "restoreUntil"
                            ]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many debts are in the trash in all"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["debts", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.deleteForever": {
      "post": {
        "operationId": "debts.deleteForever",
        "summary": "Delete debts in the trash for good",
        "description": "Delete debts that are in the trash for good, with their paybacks: the ones named (debtIds), or the whole trash (all: true). It cannot be undone, so ask the person first. Debts not in the trash are refused: debts.delete moves a debt there.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "debtIds": {
                        "description": "Debts in the trash to delete for good (from debts.trash)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A debt id (from debts.list or debts.add)"
                        }
                      },
                      "all": {
                        "description": "true: empty the whole trash instead",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "debtIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many debts were deleted for good"
                        }
                      },
                      "required": ["debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/debts.deletePerson": {
      "post": {
        "operationId": "debts.deletePerson",
        "summary": "Delete a person for good",
        "description": "Delete a person for good, with any of their debts that are in the trash. Refused while they still have debts outside the trash. It cannot be undone, so ask the person first; to just hide someone, archive them with debts.updatePerson.",
        "tags": ["debts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "personId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A person id (from debts.people)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["personId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "personId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "debts": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many trashed debts went with them"
                        }
                      },
                      "required": ["debts"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.add": {
      "post": {
        "operationId": "reminders.add",
        "summary": "Set reminders",
        "description": "Set up to 50 reminders in one call. Each has a short text, when it fires (once at a day and time, or a repeating rule) in the person's time zone, how it reaches the person (their settings unless asked otherwise), and the record it is about (a note, list, list item, expense entry or debt): when the person mentions something already in HeyBMO, find it and link it, so the reminder shows it. It reaches the person in their HeyBMO inbox when due. The answer includes the current time, for times the person gives from now.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "reminders": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "text": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 300,
                              "description": "What to be reminded of, short (\"Call mum\")"
                            },
                            "when": {
                              "oneOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "never" },
                                    "date": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    }
                                  },
                                  "required": ["repeat", "date", "time"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "daily" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N days",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 365
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "weekly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N weeks",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 52
                                    },
                                    "weekdays": {
                                      "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                      "minItems": 1,
                                      "maxItems": 7,
                                      "type": "array",
                                      "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "monthly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N months",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 12
                                    },
                                    "day": {
                                      "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                      "anyOf": [
                                        { "type": "integer", "minimum": 1, "maximum": 31 },
                                        { "type": "string", "const": "last" }
                                      ]
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "yearly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N years, on the month and day of `starts`",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                }
                              ],
                              "description": "When it fires, in its time zone. Once: { repeat: \"never\", date, time }. Repeating: daily, weekly (weekdays 1 = Monday), monthly (day, or \"last\"), yearly; every N; until a day or a number of times."
                            },
                            "timeZone": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 64,
                              "description": "A fixed time zone such as America/New_York, only when the person names one (\"9am New York time\"). Default: their own, following them when they move."
                            },
                            "delivery": {
                              "default": "default",
                              "anyOf": [
                                { "type": "string", "const": "default" },
                                {
                                  "maxItems": 3,
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "enum": ["email", "push", "desktop"]
                                  }
                                },
                                { "type": "string", "enum": ["inbox", "email", "push"] }
                              ],
                              "description": "How this one reaches the person besides the inbox: default follows their notification settings; or its own channels, several at once, which replace the settings for this reminder: email, push (a pop-up), desktop (the HeyBMO app on their computer); [] is the inbox only. To add to their usual channels (\"my usual plus email\"), read the reminders group in inbox.settings and list its channels too. Quiet hours still apply. Only set it when asked."
                            },
                            "link": {
                              "type": "object",
                              "properties": {
                                "kind": {
                                  "type": "string",
                                  "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                                },
                                "id": {
                                  "type": "string",
                                  "format": "uuid",
                                  "description": "The record id, from that feature"
                                }
                              },
                              "required": ["kind", "id"],
                              "description": "The record this reminder is about, when the person mentions one that exists (it is shown with the reminder, never changed)"
                            },
                            "unlinked": {
                              "description": "true when the words name a record HeyBMO keeps but this reminder is not about it (otherwise HeyBMO links that record)",
                              "type": "boolean",
                              "const": true
                            }
                          },
                          "required": ["text", "when"]
                        }
                      }
                    },
                    "required": ["reminders"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "reminders": [
                    {
                      "text": "Call mum",
                      "when": { "repeat": "never", "date": "2026-11-02", "time": "18:00" }
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "when": {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "never" },
                                      "date": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      }
                                    },
                                    "required": ["repeat", "date", "time"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "daily" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N days",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 365
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "weekly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N weeks",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 52
                                      },
                                      "weekdays": {
                                        "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                        "minItems": 1,
                                        "maxItems": 7,
                                        "type": "array",
                                        "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "monthly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N months",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 12
                                      },
                                      "day": {
                                        "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                        "anyOf": [
                                          { "type": "integer", "minimum": 1, "maximum": 31 },
                                          { "type": "string", "const": "last" }
                                        ]
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "yearly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N years, on the month and day of `starts`",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  }
                                ]
                              },
                              "timeZone": { "type": "string" },
                              "followsPerson": {
                                "type": "boolean",
                                "description": "The time zone follows the person when they move"
                              },
                              "next": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "date": { "type": "string", "format": "date" },
                                      "time": { "type": "string" }
                                    },
                                    "required": ["date", "time"]
                                  },
                                  { "type": "null" }
                                ],
                                "description": "The next time it fires, in its time zone; null once a one-off has fired"
                              },
                              "nextAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "delivery": {
                                "anyOf": [
                                  { "type": "string", "const": "default" },
                                  {
                                    "type": "array",
                                    "items": {
                                      "type": "string",
                                      "enum": ["email", "push", "desktop"]
                                    }
                                  }
                                ],
                                "description": "How it reaches the person besides the inbox: default follows their settings, or its own channels (email, push, desktop; [] is the inbox only)"
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "paused": { "type": "boolean" },
                              "notDone": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Times it went off and were not marked done yet"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "coming": {
                                "description": "Its next times in the window asked for (reminders.list comingDays), snoozed ones at the time they come back; left out otherwise",
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it goes off"
                                    },
                                    "date": {
                                      "type": "string",
                                      "description": "That day, in the reminder’s time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "That time, in the reminder’s time zone"
                                    },
                                    "dueAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "The time its rule gives (pass it as `at` to snooze or done)"
                                    },
                                    "snoozed": {
                                      "type": "boolean",
                                      "description": "Pushed back from dueAt to at"
                                    },
                                    "firingId": {
                                      "anyOf": [
                                        { "type": "string", "format": "uuid" },
                                        { "type": "null" }
                                      ],
                                      "description": "Set once it went off or was snoozed"
                                    }
                                  },
                                  "required": ["at", "date", "time", "dueAt", "snoozed", "firingId"]
                                }
                              }
                            },
                            "required": [
                              "id",
                              "text",
                              "when",
                              "timeZone",
                              "followsPerson",
                              "next",
                              "nextAt",
                              "delivery",
                              "link",
                              "paused",
                              "notDone",
                              "revision",
                              "createdAt"
                            ]
                          }
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        },
                        "notes": {
                          "description": "Links HeyBMO made from the words, or records the words name; tell the person",
                          "type": "array",
                          "items": { "type": "string" }
                        }
                      },
                      "required": ["reminders", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.update": {
      "post": {
        "operationId": "reminders.update",
        "summary": "Change reminders",
        "description": "Change up to 50 reminders: text, time, time zone, delivery, link, or paused. A new when replaces the old time or rule; timeZone null follows the person again; link null removes it; paused true stops it firing until set back to false. Only what is given changes. To mark one done or snooze it, use reminders.done or reminders.snooze.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "reminders": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reminderId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A reminder id (from reminders.list or reminders.add)"
                            },
                            "revision": {
                              "description": "The revision you last read. If it changed since, the change is refused so nothing is overwritten.",
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 9007199254740991
                            },
                            "text": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 300,
                              "description": "What to be reminded of, short (\"Call mum\")"
                            },
                            "when": {
                              "oneOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "never" },
                                    "date": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    }
                                  },
                                  "required": ["repeat", "date", "time"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "daily" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N days",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 365
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "weekly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N weeks",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 52
                                    },
                                    "weekdays": {
                                      "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                      "minItems": 1,
                                      "maxItems": 7,
                                      "type": "array",
                                      "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "monthly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N months",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 12
                                    },
                                    "day": {
                                      "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                      "anyOf": [
                                        { "type": "integer", "minimum": 1, "maximum": 31 },
                                        { "type": "string", "const": "last" }
                                      ]
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                },
                                {
                                  "type": "object",
                                  "properties": {
                                    "repeat": { "type": "string", "const": "yearly" },
                                    "every": {
                                      "default": 1,
                                      "description": "Every N years, on the month and day of `starts`",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                    },
                                    "starts": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The first day it can happen"
                                    },
                                    "until": {
                                      "description": "The last day it can happen",
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "times": {
                                      "description": "Stop after this many runs",
                                      "type": "integer",
                                      "minimum": 1,
                                      "maximum": 10000
                                    }
                                  },
                                  "required": ["repeat", "time", "starts"]
                                }
                              ],
                              "description": "When it fires, in its time zone. Once: { repeat: \"never\", date, time }. Repeating: daily, weekly (weekdays 1 = Monday), monthly (day, or \"last\"), yearly; every N; until a day or a number of times."
                            },
                            "timeZone": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64,
                                  "description": "A fixed time zone such as America/New_York, only when the person names one (\"9am New York time\"). Default: their own, following them when they move."
                                },
                                { "type": "null" }
                              ]
                            },
                            "delivery": {
                              "anyOf": [
                                { "type": "string", "const": "default" },
                                {
                                  "maxItems": 3,
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "enum": ["email", "push", "desktop"]
                                  }
                                },
                                { "type": "string", "enum": ["inbox", "email", "push"] }
                              ],
                              "description": "How this one reaches the person besides the inbox: default follows their notification settings; or its own channels, several at once, which replace the settings for this reminder: email, push (a pop-up), desktop (the HeyBMO app on their computer); [] is the inbox only. To add to their usual channels (\"my usual plus email\"), read the reminders group in inbox.settings and list its channels too. Quiet hours still apply. Only set it when asked."
                            },
                            "link": {
                              "anyOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "kind": {
                                      "type": "string",
                                      "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                                    },
                                    "id": {
                                      "type": "string",
                                      "format": "uuid",
                                      "description": "The record id, from that feature"
                                    }
                                  },
                                  "required": ["kind", "id"],
                                  "description": "The record this reminder is about, when the person mentions one that exists (it is shown with the reminder, never changed)"
                                },
                                { "type": "null" }
                              ]
                            },
                            "paused": { "type": "boolean" }
                          },
                          "required": ["reminderId"]
                        }
                      }
                    },
                    "required": ["reminders"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "reminders": [
                    {
                      "reminderId": "01a19279-e9c3-7c73-9705-94f082fa3a65",
                      "when": { "repeat": "never", "date": "2026-11-05", "time": "10:00" }
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "when": {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "never" },
                                      "date": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      }
                                    },
                                    "required": ["repeat", "date", "time"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "daily" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N days",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 365
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "weekly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N weeks",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 52
                                      },
                                      "weekdays": {
                                        "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                        "minItems": 1,
                                        "maxItems": 7,
                                        "type": "array",
                                        "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "monthly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N months",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 12
                                      },
                                      "day": {
                                        "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                        "anyOf": [
                                          { "type": "integer", "minimum": 1, "maximum": 31 },
                                          { "type": "string", "const": "last" }
                                        ]
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "yearly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N years, on the month and day of `starts`",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  }
                                ]
                              },
                              "timeZone": { "type": "string" },
                              "followsPerson": {
                                "type": "boolean",
                                "description": "The time zone follows the person when they move"
                              },
                              "next": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "date": { "type": "string", "format": "date" },
                                      "time": { "type": "string" }
                                    },
                                    "required": ["date", "time"]
                                  },
                                  { "type": "null" }
                                ],
                                "description": "The next time it fires, in its time zone; null once a one-off has fired"
                              },
                              "nextAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "delivery": {
                                "anyOf": [
                                  { "type": "string", "const": "default" },
                                  {
                                    "type": "array",
                                    "items": {
                                      "type": "string",
                                      "enum": ["email", "push", "desktop"]
                                    }
                                  }
                                ],
                                "description": "How it reaches the person besides the inbox: default follows their settings, or its own channels (email, push, desktop; [] is the inbox only)"
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "paused": { "type": "boolean" },
                              "notDone": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Times it went off and were not marked done yet"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "coming": {
                                "description": "Its next times in the window asked for (reminders.list comingDays), snoozed ones at the time they come back; left out otherwise",
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it goes off"
                                    },
                                    "date": {
                                      "type": "string",
                                      "description": "That day, in the reminder’s time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "That time, in the reminder’s time zone"
                                    },
                                    "dueAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "The time its rule gives (pass it as `at` to snooze or done)"
                                    },
                                    "snoozed": {
                                      "type": "boolean",
                                      "description": "Pushed back from dueAt to at"
                                    },
                                    "firingId": {
                                      "anyOf": [
                                        { "type": "string", "format": "uuid" },
                                        { "type": "null" }
                                      ],
                                      "description": "Set once it went off or was snoozed"
                                    }
                                  },
                                  "required": ["at", "date", "time", "dueAt", "snoozed", "firingId"]
                                }
                              }
                            },
                            "required": [
                              "id",
                              "text",
                              "when",
                              "timeZone",
                              "followsPerson",
                              "next",
                              "nextAt",
                              "delivery",
                              "link",
                              "paused",
                              "notDone",
                              "revision",
                              "createdAt"
                            ]
                          }
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": ["reminders", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.list": {
      "post": {
        "operationId": "reminders.list",
        "summary": "List or search reminders",
        "description": "Reminders, soonest first, with when each fires next, its rule and link, a page at a time with how many match in all. Status: upcoming (default: still to fire, not paused), repeating (not paused), paused, notDone (went off and not marked done) or all (finished one-offs too). Filter by words in the text, the kind of record (linked), the record it is about, or the days its next time falls on (nextFrom, nextTo). comingDays adds each one’s times in the next days (repeats included, snoozed ones at the time they come back), to snooze or mark done one of them ahead with its dueAt. For what went off and was missed, reminders.missed lists each time.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "status": {
                        "default": "upcoming",
                        "type": "string",
                        "enum": ["upcoming", "repeating", "paused", "notDone", "all"]
                      },
                      "query": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200,
                        "description": "Words in the text"
                      },
                      "linked": {
                        "type": "string",
                        "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                      },
                      "about": {
                        "description": "Only reminders about this record",
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string",
                            "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                          },
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The record id, from that feature"
                          }
                        },
                        "required": ["kind", "id"]
                      },
                      "nextFrom": {
                        "description": "Only those whose next time is on or after this day",
                        "type": "string",
                        "format": "date"
                      },
                      "nextTo": {
                        "description": "Only those whose next time is on or before this day",
                        "type": "string",
                        "format": "date"
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      },
                      "comingDays": {
                        "default": 0,
                        "description": "Also list each reminder’s times in this many days ahead (coming)",
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 62
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "when": {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "never" },
                                      "date": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      }
                                    },
                                    "required": ["repeat", "date", "time"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "daily" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N days",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 365
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "weekly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N weeks",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 52
                                      },
                                      "weekdays": {
                                        "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                        "minItems": 1,
                                        "maxItems": 7,
                                        "type": "array",
                                        "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "monthly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N months",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 12
                                      },
                                      "day": {
                                        "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                        "anyOf": [
                                          { "type": "integer", "minimum": 1, "maximum": 31 },
                                          { "type": "string", "const": "last" }
                                        ]
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "yearly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N years, on the month and day of `starts`",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  }
                                ]
                              },
                              "timeZone": { "type": "string" },
                              "followsPerson": {
                                "type": "boolean",
                                "description": "The time zone follows the person when they move"
                              },
                              "next": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "date": { "type": "string", "format": "date" },
                                      "time": { "type": "string" }
                                    },
                                    "required": ["date", "time"]
                                  },
                                  { "type": "null" }
                                ],
                                "description": "The next time it fires, in its time zone; null once a one-off has fired"
                              },
                              "nextAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "delivery": {
                                "anyOf": [
                                  { "type": "string", "const": "default" },
                                  {
                                    "type": "array",
                                    "items": {
                                      "type": "string",
                                      "enum": ["email", "push", "desktop"]
                                    }
                                  }
                                ],
                                "description": "How it reaches the person besides the inbox: default follows their settings, or its own channels (email, push, desktop; [] is the inbox only)"
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "paused": { "type": "boolean" },
                              "notDone": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Times it went off and were not marked done yet"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "coming": {
                                "description": "Its next times in the window asked for (reminders.list comingDays), snoozed ones at the time they come back; left out otherwise",
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it goes off"
                                    },
                                    "date": {
                                      "type": "string",
                                      "description": "That day, in the reminder’s time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "That time, in the reminder’s time zone"
                                    },
                                    "dueAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "The time its rule gives (pass it as `at` to snooze or done)"
                                    },
                                    "snoozed": {
                                      "type": "boolean",
                                      "description": "Pushed back from dueAt to at"
                                    },
                                    "firingId": {
                                      "anyOf": [
                                        { "type": "string", "format": "uuid" },
                                        { "type": "null" }
                                      ],
                                      "description": "Set once it went off or was snoozed"
                                    }
                                  },
                                  "required": ["at", "date", "time", "dueAt", "snoozed", "firingId"]
                                }
                              }
                            },
                            "required": [
                              "id",
                              "text",
                              "when",
                              "timeZone",
                              "followsPerson",
                              "next",
                              "nextAt",
                              "delivery",
                              "link",
                              "paused",
                              "notDone",
                              "revision",
                              "createdAt"
                            ]
                          }
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Reminders matching, on every page"
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": ["reminders", "nextCursor", "total", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.agenda": {
      "post": {
        "operationId": "reminders.agenda",
        "summary": "What is coming up, day by day",
        "description": "Every time reminders go off between two days, soonest first, each with its reminder, a page at a time, with how many there are in all. Repeating ones count each time, snoozed ones at the time they come back; past 62 days ahead only each reminder's next time shows. from defaults to today, no to means no end. byDay adds how many go off each day. Snooze or mark done one of them with its dueAt; reminders.list lists the reminders themselves.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "description": "First day (default: today, the person’s)",
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "description": "Last day, included (default: no end)",
                        "type": "string",
                        "format": "date"
                      },
                      "query": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200,
                        "description": "Words in the text"
                      },
                      "linked": {
                        "type": "string",
                        "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                      },
                      "about": {
                        "description": "Only reminders about this record",
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string",
                            "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                          },
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The record id, from that feature"
                          }
                        },
                        "required": ["kind", "id"]
                      },
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      },
                      "byDay": {
                        "default": false,
                        "description": "Also count the times on each day",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "times": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "at": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it goes off"
                              },
                              "date": {
                                "type": "string",
                                "description": "That day, in the reminder’s time zone"
                              },
                              "time": {
                                "type": "string",
                                "description": "That time, in the reminder’s time zone"
                              },
                              "dueAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "The time its rule gives (pass it as `at` to snooze or done)"
                              },
                              "snoozed": {
                                "type": "boolean",
                                "description": "Pushed back from dueAt to at"
                              },
                              "firingId": {
                                "anyOf": [
                                  { "type": "string", "format": "uuid" },
                                  { "type": "null" }
                                ],
                                "description": "Set once it went off or was snoozed"
                              },
                              "reminder": {
                                "type": "object",
                                "properties": {
                                  "id": { "type": "string", "format": "uuid" },
                                  "text": { "type": "string" },
                                  "when": {
                                    "oneOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "repeat": { "type": "string", "const": "never" },
                                          "date": {
                                            "type": "string",
                                            "format": "date",
                                            "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                          },
                                          "time": {
                                            "type": "string",
                                            "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                          }
                                        },
                                        "required": ["repeat", "date", "time"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "repeat": { "type": "string", "const": "daily" },
                                          "every": {
                                            "default": 1,
                                            "description": "Every N days",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 365
                                          },
                                          "time": {
                                            "type": "string",
                                            "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                          },
                                          "starts": {
                                            "type": "string",
                                            "format": "date",
                                            "description": "The first day it can happen"
                                          },
                                          "until": {
                                            "description": "The last day it can happen",
                                            "type": "string",
                                            "format": "date"
                                          },
                                          "times": {
                                            "description": "Stop after this many runs",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 10000
                                          }
                                        },
                                        "required": ["repeat", "every", "time", "starts"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "repeat": { "type": "string", "const": "weekly" },
                                          "every": {
                                            "default": 1,
                                            "description": "Every N weeks",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 52
                                          },
                                          "weekdays": {
                                            "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                            "minItems": 1,
                                            "maxItems": 7,
                                            "type": "array",
                                            "items": {
                                              "type": "integer",
                                              "minimum": 1,
                                              "maximum": 7
                                            }
                                          },
                                          "time": {
                                            "type": "string",
                                            "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                          },
                                          "starts": {
                                            "type": "string",
                                            "format": "date",
                                            "description": "The first day it can happen"
                                          },
                                          "until": {
                                            "description": "The last day it can happen",
                                            "type": "string",
                                            "format": "date"
                                          },
                                          "times": {
                                            "description": "Stop after this many runs",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 10000
                                          }
                                        },
                                        "required": ["repeat", "every", "time", "starts"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "repeat": { "type": "string", "const": "monthly" },
                                          "every": {
                                            "default": 1,
                                            "description": "Every N months",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 12
                                          },
                                          "day": {
                                            "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                            "anyOf": [
                                              { "type": "integer", "minimum": 1, "maximum": 31 },
                                              { "type": "string", "const": "last" }
                                            ]
                                          },
                                          "time": {
                                            "type": "string",
                                            "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                          },
                                          "starts": {
                                            "type": "string",
                                            "format": "date",
                                            "description": "The first day it can happen"
                                          },
                                          "until": {
                                            "description": "The last day it can happen",
                                            "type": "string",
                                            "format": "date"
                                          },
                                          "times": {
                                            "description": "Stop after this many runs",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 10000
                                          }
                                        },
                                        "required": ["repeat", "every", "time", "starts"]
                                      },
                                      {
                                        "type": "object",
                                        "properties": {
                                          "repeat": { "type": "string", "const": "yearly" },
                                          "every": {
                                            "default": 1,
                                            "description": "Every N years, on the month and day of `starts`",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 10
                                          },
                                          "time": {
                                            "type": "string",
                                            "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                          },
                                          "starts": {
                                            "type": "string",
                                            "format": "date",
                                            "description": "The first day it can happen"
                                          },
                                          "until": {
                                            "description": "The last day it can happen",
                                            "type": "string",
                                            "format": "date"
                                          },
                                          "times": {
                                            "description": "Stop after this many runs",
                                            "type": "integer",
                                            "minimum": 1,
                                            "maximum": 10000
                                          }
                                        },
                                        "required": ["repeat", "every", "time", "starts"]
                                      }
                                    ]
                                  },
                                  "timeZone": { "type": "string" },
                                  "followsPerson": {
                                    "type": "boolean",
                                    "description": "The time zone follows the person when they move"
                                  },
                                  "next": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "date": { "type": "string", "format": "date" },
                                          "time": { "type": "string" }
                                        },
                                        "required": ["date", "time"]
                                      },
                                      { "type": "null" }
                                    ],
                                    "description": "The next time it fires, in its time zone; null once a one-off has fired"
                                  },
                                  "nextAt": {
                                    "anyOf": [
                                      { "type": "string", "format": "date-time" },
                                      { "type": "null" }
                                    ]
                                  },
                                  "delivery": {
                                    "anyOf": [
                                      { "type": "string", "const": "default" },
                                      {
                                        "type": "array",
                                        "items": {
                                          "type": "string",
                                          "enum": ["email", "push", "desktop"]
                                        }
                                      }
                                    ],
                                    "description": "How it reaches the person besides the inbox: default follows their settings, or its own channels (email, push, desktop; [] is the inbox only)"
                                  },
                                  "link": {
                                    "anyOf": [
                                      {
                                        "type": "object",
                                        "properties": {
                                          "kind": { "type": "string" },
                                          "id": { "type": "string", "format": "uuid" },
                                          "state": {
                                            "type": "string",
                                            "enum": ["live", "trash", "deleted"],
                                            "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                          },
                                          "title": {
                                            "description": "Null when the record is deleted for good",
                                            "type": ["string", "null"]
                                          },
                                          "path": { "type": ["string", "null"] },
                                          "facts": {
                                            "anyOf": [
                                              {
                                                "oneOf": [
                                                  {
                                                    "type": "object",
                                                    "properties": {
                                                      "kind": {
                                                        "type": "string",
                                                        "const": "progress"
                                                      },
                                                      "left": {
                                                        "type": "integer",
                                                        "minimum": -9007199254740991,
                                                        "maximum": 9007199254740991
                                                      },
                                                      "total": {
                                                        "type": "integer",
                                                        "minimum": -9007199254740991,
                                                        "maximum": 9007199254740991
                                                      }
                                                    },
                                                    "required": ["kind", "left", "total"]
                                                  },
                                                  {
                                                    "type": "object",
                                                    "properties": {
                                                      "kind": {
                                                        "type": "string",
                                                        "const": "money"
                                                      },
                                                      "way": {
                                                        "type": "string",
                                                        "enum": ["in", "out"]
                                                      },
                                                      "amount": { "type": "number" },
                                                      "currency": { "type": "string" }
                                                    },
                                                    "required": [
                                                      "kind",
                                                      "way",
                                                      "amount",
                                                      "currency"
                                                    ]
                                                  }
                                                ]
                                              },
                                              { "type": "null" }
                                            ],
                                            "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                          }
                                        },
                                        "required": [
                                          "kind",
                                          "id",
                                          "state",
                                          "title",
                                          "path",
                                          "facts"
                                        ]
                                      },
                                      { "type": "null" }
                                    ]
                                  },
                                  "paused": { "type": "boolean" },
                                  "notDone": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991,
                                    "description": "Times it went off and were not marked done yet"
                                  },
                                  "revision": {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  "createdAt": { "type": "string", "format": "date-time" },
                                  "coming": {
                                    "description": "Its next times in the window asked for (reminders.list comingDays), snoozed ones at the time they come back; left out otherwise",
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "at": {
                                          "type": "string",
                                          "format": "date-time",
                                          "description": "When it goes off"
                                        },
                                        "date": {
                                          "type": "string",
                                          "description": "That day, in the reminder’s time zone"
                                        },
                                        "time": {
                                          "type": "string",
                                          "description": "That time, in the reminder’s time zone"
                                        },
                                        "dueAt": {
                                          "type": "string",
                                          "format": "date-time",
                                          "description": "The time its rule gives (pass it as `at` to snooze or done)"
                                        },
                                        "snoozed": {
                                          "type": "boolean",
                                          "description": "Pushed back from dueAt to at"
                                        },
                                        "firingId": {
                                          "anyOf": [
                                            { "type": "string", "format": "uuid" },
                                            { "type": "null" }
                                          ],
                                          "description": "Set once it went off or was snoozed"
                                        }
                                      },
                                      "required": [
                                        "at",
                                        "date",
                                        "time",
                                        "dueAt",
                                        "snoozed",
                                        "firingId"
                                      ]
                                    }
                                  }
                                },
                                "required": [
                                  "id",
                                  "text",
                                  "when",
                                  "timeZone",
                                  "followsPerson",
                                  "next",
                                  "nextAt",
                                  "delivery",
                                  "link",
                                  "paused",
                                  "notDone",
                                  "revision",
                                  "createdAt"
                                ]
                              }
                            },
                            "required": [
                              "at",
                              "date",
                              "time",
                              "dueAt",
                              "snoozed",
                              "firingId",
                              "reminder"
                            ]
                          }
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Times in the whole window"
                        },
                        "days": {
                          "description": "With byDay: each day that has times, how many, and what they are about",
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "date": { "type": "string", "format": "date" },
                              "count": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "kinds": { "type": "array", "items": { "type": "string" } }
                            },
                            "required": ["date", "count", "kinds"]
                          }
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": ["times", "nextCursor", "total", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.counts": {
      "post": {
        "operationId": "reminders.counts",
        "summary": "How many reminders of each sort",
        "description": "How many reminders there are of each sort, for the words or record kind asked. missed: times that went off in the last 365 days, not done. today: times going off today. upcoming: reminders with a time still to come. repeating, paused. done: times marked done. trash. kinds: live reminders by what they are about, for the words only. To list them, use reminders.agenda, reminders.list, reminders.missed or reminders.history.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "query": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200,
                        "description": "Words in the text"
                      },
                      "linked": {
                        "type": "string",
                        "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "missed": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "today": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "upcoming": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "repeating": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "paused": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "done": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "trash": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "kinds": {
                          "type": "object",
                          "propertyNames": { "type": "string" },
                          "description": "Live reminders not paused, by feature they are about (plain: none)"
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": [
                        "missed",
                        "today",
                        "upcoming",
                        "repeating",
                        "paused",
                        "done",
                        "trash",
                        "kinds",
                        "now"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.missed": {
      "post": {
        "operationId": "reminders.missed",
        "summary": "What did I miss",
        "description": "Each time a reminder went off and was not marked done, newest first: the last 30 days by default. Snoozed ones are left out until they go off again. Mark them done with reminders.done.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "days": {
                        "default": 30,
                        "description": "How far back, in days (1: since this time yesterday)",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 365
                      },
                      "dueFrom": {
                        "description": "Only times due on or after this day, in the person’s time zone",
                        "type": "string",
                        "format": "date"
                      },
                      "limit": { "default": 100, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      },
                      "query": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200,
                        "description": "Words in the text"
                      },
                      "linked": {
                        "type": "string",
                        "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                      },
                      "about": {
                        "description": "Only reminders about this record",
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string",
                            "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                          },
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The record id, from that feature"
                          }
                        },
                        "required": ["kind", "id"]
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "firings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "reminderId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "due": {
                                "type": "object",
                                "properties": {
                                  "date": { "type": "string", "format": "date" },
                                  "time": { "type": "string" }
                                },
                                "required": ["date", "time"],
                                "description": "When it was due, in the person’s time zone"
                              },
                              "dueAt": { "type": "string", "format": "date-time" },
                              "firedAt": { "type": "string", "format": "date-time" },
                              "done": { "type": "boolean" },
                              "snoozedUntil": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              }
                            },
                            "required": [
                              "id",
                              "reminderId",
                              "text",
                              "due",
                              "dueAt",
                              "firedAt",
                              "done",
                              "snoozedUntil",
                              "link"
                            ]
                          }
                        },
                        "more": { "type": "boolean" },
                        "nextCursor": { "type": ["string", "null"] },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Times missed in the whole window"
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": ["firings", "more", "nextCursor", "total", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.history": {
      "post": {
        "operationId": "reminders.history",
        "summary": "Reminders marked done",
        "description": "Each time a reminder went off and was marked done, the most recently done first, a page at a time, with how many there are in all. Undo one with reminders.done (undo: true).",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 200 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      },
                      "query": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200,
                        "description": "Words in the text"
                      },
                      "linked": {
                        "type": "string",
                        "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                      },
                      "about": {
                        "description": "Only reminders about this record",
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string",
                            "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                          },
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The record id, from that feature"
                          }
                        },
                        "required": ["kind", "id"]
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "firings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "reminderId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "due": {
                                "type": "object",
                                "properties": {
                                  "date": { "type": "string", "format": "date" },
                                  "time": { "type": "string" }
                                },
                                "required": ["date", "time"],
                                "description": "When it was due, in the person’s time zone"
                              },
                              "dueAt": { "type": "string", "format": "date-time" },
                              "firedAt": { "type": "string", "format": "date-time" },
                              "done": { "type": "boolean" },
                              "snoozedUntil": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              }
                            },
                            "required": [
                              "id",
                              "reminderId",
                              "text",
                              "due",
                              "dueAt",
                              "firedAt",
                              "done",
                              "snoozedUntil",
                              "link"
                            ]
                          }
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["firings", "nextCursor", "total"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.done": {
      "post": {
        "operationId": "reminders.done",
        "summary": "Mark reminders done",
        "description": "Mark reminders done. With firingIds: those times they went off (from reminders.missed). With reminderIds: every time each went off and is not done; if none, its next time ahead, so it stays quiet then (a repeating one still fires after that). With upcoming: those exact times ahead (dueAt from reminders.list comingDays), so a repeating one skips just that time. undo: true (firingIds only) makes them not done again: a time that went off is missed again, a time marked done ahead goes off as planned. Stopping a reminder for good is reminders.delete.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "firingIds": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A firing id: one time a reminder went off (from reminders.missed or reminders.list)"
                        }
                      },
                      "reminderIds": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A reminder id (from reminders.list or reminders.add)"
                        }
                      },
                      "upcoming": {
                        "description": "Times still ahead to mark done now, so they stay quiet",
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "reminderId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A reminder id (from reminders.list or reminders.add)"
                            },
                            "at": {
                              "type": "string",
                              "format": "date-time",
                              "description": "One of its times still to come: a dueAt from reminders.list with comingDays"
                            }
                          },
                          "required": ["reminderId", "at"]
                        }
                      },
                      "undo": {
                        "default": false,
                        "description": "Not done again (with firingIds)",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "firingIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "firings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "reminderId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "due": {
                                "type": "object",
                                "properties": {
                                  "date": { "type": "string", "format": "date" },
                                  "time": { "type": "string" }
                                },
                                "required": ["date", "time"],
                                "description": "When it was due, in the person’s time zone"
                              },
                              "dueAt": { "type": "string", "format": "date-time" },
                              "firedAt": { "type": "string", "format": "date-time" },
                              "done": { "type": "boolean" },
                              "snoozedUntil": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              }
                            },
                            "required": [
                              "id",
                              "reminderId",
                              "text",
                              "due",
                              "dueAt",
                              "firedAt",
                              "done",
                              "snoozedUntil",
                              "link"
                            ]
                          }
                        },
                        "nothingToMark": {
                          "type": "array",
                          "items": { "type": "string", "format": "uuid" },
                          "description": "Reminders that never went off and have no next time (finished)"
                        }
                      },
                      "required": ["firings", "nothingToMark"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.snooze": {
      "post": {
        "operationId": "reminders.snooze",
        "summary": "Snooze a reminder",
        "description": "Make a reminder come back later: for 10m, 1h, evening (18:00), tomorrow (08:00 the next day), or until a given day and time, in the person’s time zone. Name the time it went off (firingId), or the reminder: its latest time not done, else its next time ahead. With reminderId and at (a dueAt from reminders.list comingDays), that time ahead is pushed back. Presets count from now, or from the time it would come when that is later (1h on a 15:00 reminder: 16:00). A repeating reminder keeps its rule: only that one time moves. A done one cannot be snoozed. To push back several at once, give targets (each a firingId, or a reminderId with an optional at) instead of firingId/reminderId; they all move the same way, together or not at all.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "firingId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A firing id: one time a reminder went off (from reminders.missed or reminders.list)"
                      },
                      "reminderId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "A reminder id (from reminders.list or reminders.add)"
                      },
                      "at": {
                        "description": "With reminderId: the time ahead to push back",
                        "type": "string",
                        "format": "date-time"
                      },
                      "targets": {
                        "description": "Several to push back the same way, instead of firingId or reminderId",
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "firingId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A firing id: one time a reminder went off (from reminders.missed or reminders.list)"
                            },
                            "reminderId": {
                              "type": "string",
                              "format": "uuid",
                              "description": "A reminder id (from reminders.list or reminders.add)"
                            },
                            "at": {
                              "description": "With reminderId: the time ahead to push back",
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        }
                      },
                      "for": {
                        "description": "10m, 1h, evening (18:00) or tomorrow (08:00)",
                        "type": "string",
                        "enum": ["10m", "1h", "evening", "tomorrow"]
                      },
                      "until": {
                        "description": "A given day and time instead of a preset",
                        "type": "object",
                        "properties": {
                          "date": { "type": "string", "format": "date" },
                          "time": { "type": "string" }
                        },
                        "required": ["date", "time"]
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": { "reminderId": "01a19279-e9c3-7c73-9705-94f082fa3a65", "for": "1h" }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "firing": {
                          "type": "object",
                          "properties": {
                            "id": { "type": "string", "format": "uuid" },
                            "reminderId": { "type": "string", "format": "uuid" },
                            "text": { "type": "string" },
                            "due": {
                              "type": "object",
                              "properties": {
                                "date": { "type": "string", "format": "date" },
                                "time": { "type": "string" }
                              },
                              "required": ["date", "time"],
                              "description": "When it was due, in the person’s time zone"
                            },
                            "dueAt": { "type": "string", "format": "date-time" },
                            "firedAt": { "type": "string", "format": "date-time" },
                            "done": { "type": "boolean" },
                            "snoozedUntil": {
                              "anyOf": [
                                { "type": "string", "format": "date-time" },
                                { "type": "null" }
                              ]
                            },
                            "link": {
                              "anyOf": [
                                {
                                  "type": "object",
                                  "properties": {
                                    "kind": { "type": "string" },
                                    "id": { "type": "string", "format": "uuid" },
                                    "state": {
                                      "type": "string",
                                      "enum": ["live", "trash", "deleted"],
                                      "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                    },
                                    "title": {
                                      "description": "Null when the record is deleted for good",
                                      "type": ["string", "null"]
                                    },
                                    "path": { "type": ["string", "null"] },
                                    "facts": {
                                      "anyOf": [
                                        {
                                          "oneOf": [
                                            {
                                              "type": "object",
                                              "properties": {
                                                "kind": { "type": "string", "const": "progress" },
                                                "left": {
                                                  "type": "integer",
                                                  "minimum": -9007199254740991,
                                                  "maximum": 9007199254740991
                                                },
                                                "total": {
                                                  "type": "integer",
                                                  "minimum": -9007199254740991,
                                                  "maximum": 9007199254740991
                                                }
                                              },
                                              "required": ["kind", "left", "total"]
                                            },
                                            {
                                              "type": "object",
                                              "properties": {
                                                "kind": { "type": "string", "const": "money" },
                                                "way": { "type": "string", "enum": ["in", "out"] },
                                                "amount": { "type": "number" },
                                                "currency": { "type": "string" }
                                              },
                                              "required": ["kind", "way", "amount", "currency"]
                                            }
                                          ]
                                        },
                                        { "type": "null" }
                                      ],
                                      "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                    }
                                  },
                                  "required": ["kind", "id", "state", "title", "path", "facts"]
                                },
                                { "type": "null" }
                              ]
                            }
                          },
                          "required": [
                            "id",
                            "reminderId",
                            "text",
                            "due",
                            "dueAt",
                            "firedAt",
                            "done",
                            "snoozedUntil",
                            "link"
                          ],
                          "description": "The first one pushed back"
                        },
                        "firings": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "reminderId": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "due": {
                                "type": "object",
                                "properties": {
                                  "date": { "type": "string", "format": "date" },
                                  "time": { "type": "string" }
                                },
                                "required": ["date", "time"],
                                "description": "When it was due, in the person’s time zone"
                              },
                              "dueAt": { "type": "string", "format": "date-time" },
                              "firedAt": { "type": "string", "format": "date-time" },
                              "done": { "type": "boolean" },
                              "snoozedUntil": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              }
                            },
                            "required": [
                              "id",
                              "reminderId",
                              "text",
                              "due",
                              "dueAt",
                              "firedAt",
                              "done",
                              "snoozedUntil",
                              "link"
                            ]
                          },
                          "description": "Every one pushed back, in the order given"
                        },
                        "now": {
                          "type": "object",
                          "properties": {
                            "date": { "type": "string", "format": "date" },
                            "time": { "type": "string" },
                            "timeZone": { "type": "string" }
                          },
                          "required": ["date", "time", "timeZone"],
                          "description": "Now, in the person’s time zone"
                        }
                      },
                      "required": ["firing", "firings", "now"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.bulk": {
      "post": {
        "operationId": "reminders.bulk",
        "summary": "Act on every reminder that matches",
        "description": "Mark done, snooze, pause, resume or restore every reminder or time in a section that matches the filter, up to 200 per call: while next is not null, call again with after: next for the rest. done and snooze act on times (missed, today, upcoming) or on repeating reminders' next time; pause on reminders with times or repeating ones; resume on paused ones; restore on the trash. For a few named ones, use reminders.done, reminders.snooze or reminders.update; to move all that match to the trash, reminders.delete with matching.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "matching": {
                        "type": "object",
                        "properties": {
                          "section": {
                            "type": "string",
                            "enum": ["missed", "today", "upcoming", "repeating", "paused", "trash"],
                            "description": "missed (went off in the last 365 days, not done), today, upcoming (times from today on, as reminders.agenda lists them), repeating, paused or trash"
                          },
                          "query": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200,
                            "description": "Words in the text"
                          },
                          "linked": {
                            "type": "string",
                            "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                          },
                          "about": {
                            "description": "Only reminders about this record",
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                              },
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "The record id, from that feature"
                              }
                            },
                            "required": ["kind", "id"]
                          },
                          "day": {
                            "description": "upcoming: only the times on this day",
                            "type": "string",
                            "format": "date"
                          }
                        },
                        "required": ["section"],
                        "description": "Every reminder or time in a section that matches the filter"
                      },
                      "do": {
                        "type": "string",
                        "enum": ["done", "snooze", "pause", "resume", "restore"]
                      },
                      "for": {
                        "description": "snooze: 10m, 1h, evening or tomorrow",
                        "type": "string",
                        "enum": ["10m", "1h", "evening", "tomorrow"]
                      },
                      "until": {
                        "description": "snooze: a given day and time instead",
                        "type": "object",
                        "properties": {
                          "date": { "type": "string", "format": "date" },
                          "time": { "type": "string" }
                        },
                        "required": ["date", "time"]
                      },
                      "after": {
                        "description": "next from the previous call",
                        "type": "string",
                        "maxLength": 100
                      }
                    },
                    "required": ["matching", "do"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "matching": { "section": "missed" }, "do": "done" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "changed": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Rows acted on by this call"
                        },
                        "next": {
                          "description": "Pass as after to carry on; null when all are done",
                          "type": ["string", "null"]
                        }
                      },
                      "required": ["changed", "next"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.delete": {
      "post": {
        "operationId": "reminders.delete",
        "summary": "Move reminders to the trash",
        "description": "Move reminders to the trash: they stop firing, and can be restored with reminders.restore for 30 days, then they are deleted for good. Name them (reminderIds), or give matching for every reminder in a section that matches (a batch per call: while next is not null, call again with after: next). To stop one for a while, pause it with reminders.update instead.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "reminderIds": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A reminder id (from reminders.list or reminders.add)"
                        }
                      },
                      "matching": {
                        "description": "Instead of reminderIds: every reminder in a section that matches, up to 200 per call",
                        "type": "object",
                        "properties": {
                          "section": {
                            "type": "string",
                            "enum": ["missed", "today", "upcoming", "repeating", "paused", "trash"],
                            "description": "missed (went off in the last 365 days, not done), today, upcoming (times from today on, as reminders.agenda lists them), repeating, paused or trash"
                          },
                          "query": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200,
                            "description": "Words in the text"
                          },
                          "linked": {
                            "type": "string",
                            "description": "Only reminders about a record of this feature (notes, lists, debts, expenses), or plain: about nothing"
                          },
                          "about": {
                            "description": "Only reminders about this record",
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "description": "The kind of record, e.g. notes.note, lists.item, debts.debt"
                              },
                              "id": {
                                "type": "string",
                                "format": "uuid",
                                "description": "The record id, from that feature"
                              }
                            },
                            "required": ["kind", "id"]
                          },
                          "day": {
                            "description": "upcoming: only the times on this day",
                            "type": "string",
                            "format": "date"
                          }
                        },
                        "required": ["section"]
                      },
                      "after": {
                        "description": "With matching: next from the previous call",
                        "type": "string",
                        "maxLength": 100
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "reminderIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "deleted": {
                          "type": "array",
                          "items": { "type": "string", "format": "uuid" }
                        },
                        "deletedAt": { "type": "string", "format": "date-time" },
                        "restoreUntil": { "type": "string", "format": "date-time" },
                        "next": {
                          "description": "With matching: pass as after to carry on; null when done",
                          "type": ["string", "null"]
                        }
                      },
                      "required": ["deleted", "deletedAt", "restoreUntil", "next"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.restore": {
      "post": {
        "operationId": "reminders.restore",
        "summary": "Restore reminders from the trash",
        "description": "Bring reminders back from the trash; they fire again from their next time (times missed while in the trash are not sent).",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "reminderIds": {
                        "minItems": 1,
                        "maxItems": 50,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A reminder id (from reminders.list or reminders.add)"
                        }
                      }
                    },
                    "required": ["reminderIds"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "reminderIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "when": {
                                "oneOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "never" },
                                      "date": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "A calendar date, YYYY-MM-DD, in the schedule time zone"
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      }
                                    },
                                    "required": ["repeat", "date", "time"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "daily" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N days",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 365
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "weekly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N weeks",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 52
                                      },
                                      "weekdays": {
                                        "description": "1 = Monday ... 7 = Sunday; default: the weekday of `starts`",
                                        "minItems": 1,
                                        "maxItems": 7,
                                        "type": "array",
                                        "items": { "type": "integer", "minimum": 1, "maximum": 7 }
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "monthly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N months",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 12
                                      },
                                      "day": {
                                        "description": "Day of the month (29-31 fall on the last day in shorter months); default: the day of `starts`",
                                        "anyOf": [
                                          { "type": "integer", "minimum": 1, "maximum": 31 },
                                          { "type": "string", "const": "last" }
                                        ]
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  },
                                  {
                                    "type": "object",
                                    "properties": {
                                      "repeat": { "type": "string", "const": "yearly" },
                                      "every": {
                                        "default": 1,
                                        "description": "Every N years, on the month and day of `starts`",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10
                                      },
                                      "time": {
                                        "type": "string",
                                        "description": "A 24-hour wall-clock time, HH:MM, in the schedule time zone"
                                      },
                                      "starts": {
                                        "type": "string",
                                        "format": "date",
                                        "description": "The first day it can happen"
                                      },
                                      "until": {
                                        "description": "The last day it can happen",
                                        "type": "string",
                                        "format": "date"
                                      },
                                      "times": {
                                        "description": "Stop after this many runs",
                                        "type": "integer",
                                        "minimum": 1,
                                        "maximum": 10000
                                      }
                                    },
                                    "required": ["repeat", "every", "time", "starts"]
                                  }
                                ]
                              },
                              "timeZone": { "type": "string" },
                              "followsPerson": {
                                "type": "boolean",
                                "description": "The time zone follows the person when they move"
                              },
                              "next": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "date": { "type": "string", "format": "date" },
                                      "time": { "type": "string" }
                                    },
                                    "required": ["date", "time"]
                                  },
                                  { "type": "null" }
                                ],
                                "description": "The next time it fires, in its time zone; null once a one-off has fired"
                              },
                              "nextAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "delivery": {
                                "anyOf": [
                                  { "type": "string", "const": "default" },
                                  {
                                    "type": "array",
                                    "items": {
                                      "type": "string",
                                      "enum": ["email", "push", "desktop"]
                                    }
                                  }
                                ],
                                "description": "How it reaches the person besides the inbox: default follows their settings, or its own channels (email, push, desktop; [] is the inbox only)"
                              },
                              "link": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "kind": { "type": "string" },
                                      "id": { "type": "string", "format": "uuid" },
                                      "state": {
                                        "type": "string",
                                        "enum": ["live", "trash", "deleted"],
                                        "description": "live: there as normal. trash: in its feature's trash (it can be restored; path opens that trash). deleted: deleted for good or its feature switched off (title and path are null)"
                                      },
                                      "title": {
                                        "description": "Null when the record is deleted for good",
                                        "type": ["string", "null"]
                                      },
                                      "path": { "type": ["string", "null"] },
                                      "facts": {
                                        "anyOf": [
                                          {
                                            "oneOf": [
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "progress" },
                                                  "left": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  },
                                                  "total": {
                                                    "type": "integer",
                                                    "minimum": -9007199254740991,
                                                    "maximum": 9007199254740991
                                                  }
                                                },
                                                "required": ["kind", "left", "total"]
                                              },
                                              {
                                                "type": "object",
                                                "properties": {
                                                  "kind": { "type": "string", "const": "money" },
                                                  "way": {
                                                    "type": "string",
                                                    "enum": ["in", "out"]
                                                  },
                                                  "amount": { "type": "number" },
                                                  "currency": { "type": "string" }
                                                },
                                                "required": ["kind", "way", "amount", "currency"]
                                              }
                                            ]
                                          },
                                          { "type": "null" }
                                        ],
                                        "description": "A list: how many items are left of all. A debt or expense: the money left or spent, in the home currency when known; in = owed to the person or income, out = they owe or spent"
                                      }
                                    },
                                    "required": ["kind", "id", "state", "title", "path", "facts"]
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "paused": { "type": "boolean" },
                              "notDone": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "Times it went off and were not marked done yet"
                              },
                              "revision": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "createdAt": { "type": "string", "format": "date-time" },
                              "coming": {
                                "description": "Its next times in the window asked for (reminders.list comingDays), snoozed ones at the time they come back; left out otherwise",
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "at": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it goes off"
                                    },
                                    "date": {
                                      "type": "string",
                                      "description": "That day, in the reminder’s time zone"
                                    },
                                    "time": {
                                      "type": "string",
                                      "description": "That time, in the reminder’s time zone"
                                    },
                                    "dueAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "The time its rule gives (pass it as `at` to snooze or done)"
                                    },
                                    "snoozed": {
                                      "type": "boolean",
                                      "description": "Pushed back from dueAt to at"
                                    },
                                    "firingId": {
                                      "anyOf": [
                                        { "type": "string", "format": "uuid" },
                                        { "type": "null" }
                                      ],
                                      "description": "Set once it went off or was snoozed"
                                    }
                                  },
                                  "required": ["at", "date", "time", "dueAt", "snoozed", "firingId"]
                                }
                              }
                            },
                            "required": [
                              "id",
                              "text",
                              "when",
                              "timeZone",
                              "followsPerson",
                              "next",
                              "nextAt",
                              "delivery",
                              "link",
                              "paused",
                              "notDone",
                              "revision",
                              "createdAt"
                            ]
                          }
                        }
                      },
                      "required": ["reminders"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.trash": {
      "post": {
        "operationId": "reminders.trash",
        "summary": "List the trash",
        "description": "Reminders in the trash, most recently deleted first, with until when each can be restored, a page at a time with how many there are in all.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "limit": { "default": 50, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "text": { "type": "string" },
                              "deletedAt": { "type": "string", "format": "date-time" },
                              "restoreUntil": { "type": "string", "format": "date-time" }
                            },
                            "required": ["id", "text", "deletedAt", "restoreUntil"]
                          }
                        },
                        "nextCursor": { "type": ["string", "null"] },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        }
                      },
                      "required": ["reminders", "nextCursor", "total"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/reminders.deleteForever": {
      "post": {
        "operationId": "reminders.deleteForever",
        "summary": "Delete reminders in the trash for good",
        "description": "Delete reminders that are in the trash for good, with their schedule and the record of when they went off: the ones named (reminderIds), or the whole trash (all: true). It cannot be undone, so ask the person first. Reminders not in the trash are refused: reminders.delete moves a reminder there.",
        "tags": ["reminders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "reminderIds": {
                        "description": "Reminders in the trash to delete for good (from reminders.trash)",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "description": "A reminder id (from reminders.list or reminders.add)"
                        }
                      },
                      "all": {
                        "description": "true: empty the trash instead, up to 200 per call (call again while left is above 0)",
                        "type": "boolean"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    }
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "reminderIds": ["01a19279-e9c3-7c73-9705-94f082fa3a65"] } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "reminders": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many reminders were deleted for good"
                        },
                        "firings": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many times they went off, whose record went with them"
                        },
                        "left": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Reminders still in the trash: with all, call again while above 0"
                        }
                      },
                      "required": ["reminders", "firings", "left"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.events": {
      "post": {
        "operationId": "automations.events",
        "summary": "List what automations can watch",
        "description": "List the events automations can watch (e.g. a list is complete), what each can be narrowed to (e.g. one list) and the {fill-ins} its message can use, and the actions an automation can run besides sending a message (e.g. create a reminder). Read this before automations.create.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" },
                              "narrowBy": { "type": "array", "items": { "type": "string" } },
                              "fillIns": { "type": "object", "propertyNames": { "type": "string" } }
                            },
                            "required": ["id", "title", "description", "narrowBy", "fillIns"]
                          }
                        },
                        "actions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string" },
                              "title": { "type": "string" },
                              "description": { "type": "string" }
                            },
                            "required": ["id", "title", "description"]
                          }
                        }
                      },
                      "required": ["events", "actions"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.create": {
      "post": {
        "operationId": "automations.create",
        "summary": "Create an automation",
        "description": "Make an automation: when an event happens (see automations.events), send the person a message to their inbox, and by email when asked, right away, after a delay or at a time of day. Narrow it to one list (or other item) with narrowTo; once makes it switch itself off after the first time. With an action (e.g. reminders.create) it does that instead, the message being its text: a reminder can be snoozed and marked done, and points at what the event was about. Make one only when the person asks for it or agrees when offered. Messages only ever go to the person. Limits keep it quiet, so tell the person about them when it watches something that happens often: at most one message every 10 minutes per automation (more are combined into one), 50 a day per automation, and 20 emails and 200 messages a day in all; the person is told in their inbox when one is reached.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100,
                        "description": "A short name; also the message title"
                      },
                      "event": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 80,
                        "description": "The event id, e.g. lists.listCompleted"
                      },
                      "narrowTo": {
                        "default": {},
                        "description": "Only when the event is about this, e.g. {\"listId\": \"<id>\"}",
                        "type": "object",
                        "propertyNames": { "type": "string" }
                      },
                      "message": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 1000,
                        "description": "The message to send; {fill-ins} from the event (see automations.events) are filled in"
                      },
                      "email": {
                        "default": false,
                        "description": "Also send it by email (always in the inbox)",
                        "type": "boolean"
                      },
                      "action": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 80,
                        "description": "An action to run when it fires, e.g. reminders.create (see automations.events); the message is its text. Without it, the message is sent."
                      },
                      "delayMinutes": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 43200,
                        "description": "Wait this many minutes first (up to 30 days)"
                      },
                      "atTime": {
                        "type": "string",
                        "description": "Or send at the next such time of day, HH:MM, in the person’s time zone"
                      },
                      "once": { "default": false, "type": "boolean" }
                    },
                    "required": ["name", "event", "message"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "name": "List finished",
                  "event": "lists.listCompleted",
                  "narrowTo": { "listId": "01a19279-e9c3-7c73-9705-94f082fa3a65" },
                  "message": "{list} is complete.",
                  "email": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "event": { "type": "string" },
                        "eventTitle": { "type": "string" },
                        "narrowTo": { "type": "object", "propertyNames": { "type": "string" } },
                        "message": { "type": "string" },
                        "email": { "type": "boolean" },
                        "action": {
                          "description": "The action it runs with its message (see automations.events); null sends the message",
                          "type": ["string", "null"]
                        },
                        "delayMinutes": {
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            { "type": "null" }
                          ]
                        },
                        "atTime": { "type": ["string", "null"] },
                        "once": { "type": "boolean" },
                        "enabled": { "type": "boolean" },
                        "lastFiredAt": {
                          "anyOf": [{ "type": "string", "format": "date-time" }, { "type": "null" }]
                        },
                        "firedToday": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many times it fired today (UTC)"
                        },
                        "pausedToday": {
                          "type": "boolean",
                          "description": "It reached its daily limit; it starts again tomorrow and the person was told"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "event",
                        "eventTitle",
                        "narrowTo",
                        "message",
                        "email",
                        "action",
                        "delayMinutes",
                        "atTime",
                        "once",
                        "enabled",
                        "lastFiredAt",
                        "firedToday",
                        "pausedToday"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.list": {
      "post": {
        "operationId": "automations.list",
        "summary": "List automations",
        "description": "List the person’s automations, newest first: what each watches, its message, whether it is on, when it last fired, how often it fired today and whether it is paused until tomorrow by its daily limit.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": { "type": "object", "properties": {} },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": {} }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "automations": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "name": { "type": "string" },
                              "event": { "type": "string" },
                              "eventTitle": { "type": "string" },
                              "narrowTo": {
                                "type": "object",
                                "propertyNames": { "type": "string" }
                              },
                              "message": { "type": "string" },
                              "email": { "type": "boolean" },
                              "action": {
                                "description": "The action it runs with its message (see automations.events); null sends the message",
                                "type": ["string", "null"]
                              },
                              "delayMinutes": {
                                "anyOf": [
                                  {
                                    "type": "integer",
                                    "minimum": -9007199254740991,
                                    "maximum": 9007199254740991
                                  },
                                  { "type": "null" }
                                ]
                              },
                              "atTime": { "type": ["string", "null"] },
                              "once": { "type": "boolean" },
                              "enabled": { "type": "boolean" },
                              "lastFiredAt": {
                                "anyOf": [
                                  { "type": "string", "format": "date-time" },
                                  { "type": "null" }
                                ]
                              },
                              "firedToday": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991,
                                "description": "How many times it fired today (UTC)"
                              },
                              "pausedToday": {
                                "type": "boolean",
                                "description": "It reached its daily limit; it starts again tomorrow and the person was told"
                              }
                            },
                            "required": [
                              "id",
                              "name",
                              "event",
                              "eventTitle",
                              "narrowTo",
                              "message",
                              "email",
                              "action",
                              "delayMinutes",
                              "atTime",
                              "once",
                              "enabled",
                              "lastFiredAt",
                              "firedToday",
                              "pausedToday"
                            ]
                          }
                        }
                      },
                      "required": ["automations"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.update": {
      "post": {
        "operationId": "automations.update",
        "summary": "Change an automation",
        "description": "Change an automation’s name, message, email, action, timing or whether it runs only once. action null sends the message instead; null timing removes a delay or time; enabled: false pauses it and true turns it back on. What it watches stays; to watch something else, make a new one.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "automationId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "An automation id (from automations.list)"
                      },
                      "name": { "type": "string", "minLength": 1, "maxLength": 100 },
                      "message": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 1000,
                        "description": "The message to send; {fill-ins} from the event (see automations.events) are filled in"
                      },
                      "email": { "type": "boolean" },
                      "action": {
                        "anyOf": [
                          {
                            "type": "string",
                            "minLength": 3,
                            "maxLength": 80,
                            "description": "An action to run when it fires, e.g. reminders.create (see automations.events); the message is its text. Without it, the message is sent."
                          },
                          { "type": "null" }
                        ]
                      },
                      "delayMinutes": {
                        "anyOf": [
                          {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 43200,
                            "description": "Wait this many minutes first (up to 30 days)"
                          },
                          { "type": "null" }
                        ]
                      },
                      "atTime": {
                        "anyOf": [
                          {
                            "type": "string",
                            "description": "Or send at the next such time of day, HH:MM, in the person’s time zone"
                          },
                          { "type": "null" }
                        ]
                      },
                      "once": { "type": "boolean" },
                      "enabled": { "type": "boolean" }
                    },
                    "required": ["automationId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": {
                "input": {
                  "automationId": "01a19279-eb99-775d-bebf-12c59f611dfb",
                  "enabled": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "name": { "type": "string" },
                        "event": { "type": "string" },
                        "eventTitle": { "type": "string" },
                        "narrowTo": { "type": "object", "propertyNames": { "type": "string" } },
                        "message": { "type": "string" },
                        "email": { "type": "boolean" },
                        "action": {
                          "description": "The action it runs with its message (see automations.events); null sends the message",
                          "type": ["string", "null"]
                        },
                        "delayMinutes": {
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            { "type": "null" }
                          ]
                        },
                        "atTime": { "type": ["string", "null"] },
                        "once": { "type": "boolean" },
                        "enabled": { "type": "boolean" },
                        "lastFiredAt": {
                          "anyOf": [{ "type": "string", "format": "date-time" }, { "type": "null" }]
                        },
                        "firedToday": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many times it fired today (UTC)"
                        },
                        "pausedToday": {
                          "type": "boolean",
                          "description": "It reached its daily limit; it starts again tomorrow and the person was told"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "event",
                        "eventTitle",
                        "narrowTo",
                        "message",
                        "email",
                        "action",
                        "delayMinutes",
                        "atTime",
                        "once",
                        "enabled",
                        "lastFiredAt",
                        "firedToday",
                        "pausedToday"
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.delete": {
      "post": {
        "operationId": "automations.delete",
        "summary": "Delete an automation",
        "description": "Delete an automation for good. Messages already on their way are not sent. To stop it for a while, pause it with automations.update instead.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "automationId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "An automation id (from automations.list)"
                      },
                      "confirm": {
                        "description": "Set to true once the person agreed. Without it nothing is deleted and you get a description of what would be.",
                        "type": "boolean"
                      }
                    },
                    "required": ["automationId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "automationId": "01a19279-eb99-775d-bebf-12c59f611dfb" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string", "format": "uuid" },
                        "deleted": { "type": "boolean", "const": true }
                      },
                      "required": ["id", "deleted"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/ops/automations.runs": {
      "post": {
        "operationId": "automations.runs",
        "summary": "What an automation did",
        "description": "Each time an automation fired, newest first: when, and what it did: sent its message (by email too or not), ran its action, was skipped (and why) or failed. Kept for 90 days, the latest 200 per automation.",
        "tags": ["automations"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["input"],
                "properties": {
                  "input": {
                    "type": "object",
                    "properties": {
                      "automationId": {
                        "type": "string",
                        "format": "uuid",
                        "description": "An automation id (from automations.list)"
                      },
                      "limit": { "default": 20, "type": "integer", "minimum": 1, "maximum": 100 },
                      "cursor": {
                        "type": "string",
                        "description": "nextCursor from the previous page"
                      }
                    },
                    "required": ["automationId"]
                  },
                  "spaceId": { "type": "string", "format": "uuid" }
                }
              },
              "example": { "input": { "automationId": "01a19279-e9c3-7c73-9705-94f082fa3a65" } }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The operation output",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "object",
                      "properties": {
                        "runs": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": { "type": "string", "format": "uuid" },
                              "at": { "type": "string", "format": "date-time" },
                              "outcome": {
                                "type": "string",
                                "enum": ["sent", "acted", "skipped", "failed"],
                                "description": "sent (a message), acted (its action ran), skipped or failed"
                              },
                              "reason": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": [
                                      "dailyLimit",
                                      "spaceLimit",
                                      "featureOff",
                                      "actionOff",
                                      "emailLimit",
                                      "error"
                                    ]
                                  },
                                  { "type": "null" }
                                ],
                                "description": "dailyLimit, spaceLimit, featureOff, actionOff (skipped); emailLimit (sent, inbox only); error (failed)"
                              },
                              "email": { "type": "boolean", "description": "Also sent by email" },
                              "text": {
                                "type": "string",
                                "description": "The message as sent, cut short"
                              }
                            },
                            "required": ["id", "at", "outcome", "reason", "email", "text"]
                          }
                        },
                        "total": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "How many runs are kept for it in all"
                        },
                        "nextCursor": { "type": ["string", "null"] }
                      },
                      "required": ["runs", "total", "nextCursor"]
                    }
                  }
                }
              }
            }
          },
          "default": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  }
}
